《数据结构汇总》
闭关。
P2234 [HNOI2002]营业额统计
直接splay插入就可以了。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 2e4 + 5; const double eps = 1e-10; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e8 #define dbg(ax) cout << "now this num is " << ax << endl; inline int read() { int f = 1;int x = 0;char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } inline long long ADD(long long x,long long y) {return (x + y) % Mod;} inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;} inline long long MUL(long long x,long long y) {return x * y % Mod;} int f[N],cnt[N],value[N],sons[N][2],sz[N],allsz,rt; inline bool get_which(int x) {return sons[f[x]][1] == x;} inline void update(int x) { if(x) { sz[x] = cnt[x]; if(sons[x][0]) sz[x] += sz[sons[x][0]]; if(sons[x][1]) sz[x] += sz[sons[x][1]]; } return ; } inline void Clear(int x) {sons[x][0] = sons[x][1] = f[x] = sz[x] = cnt[x] = value[x] = 0;} inline void rotate(int x) {//旋转 int fr = f[x],g_fr = f[fr],w_son = get_which(x); sons[fr][w_son] = sons[x][w_son ^ 1]; f[sons[fr][w_son]] = fr; sons[x][w_son ^ 1] = fr; f[fr] = x; f[x] = g_fr; if(g_fr) sons[g_fr][sons[g_fr][1] == fr] = x; update(fr); update(x); } inline void splay(int x) { for(int i;i = f[x];rotate(x)) if(f[i]) rotate((get_which(x) == get_which(i)) ? i : x); rt = x; } inline void insert(int x) { if(!rt) { rt = ++allsz; sons[allsz][0] = sons[allsz][1] = f[allsz] = 0; sz[allsz] = cnt[allsz]++; value[allsz] = x; return ; } int now = rt,fa = 0; while(1) { if(x == value[now]) { cnt[now]++; update(now); update(fa); splay(now); break; } fa = now; now = sons[now][value[now] < x]; if(!now) { f[++allsz] = fa; sons[allsz][0] = sons[allsz][1] = 0; sz[allsz] = cnt[allsz] = 1; sons[fa][value[fa] < x] = allsz; value[allsz] = x; update(fa); splay(allsz); break; } } } inline int find_num(int x) {//查询排名为x的数 int now = rt; while(1) { if(sons[now][0] && x <= sz[sons[now][0]]) now = sons[now][0]; else { int temp = (sons[now][0] ? sz[sons[now][0]] : 0) + cnt[now]; if(x <= temp) return value[now]; x -= temp; now = sons[now][1]; } } } inline int find_rank(int x) {//查询x的排名 int now = rt,ans = 0; while(1) { if(x < value[now]) now = sons[now][0]; else { ans += (sons[now][0] ? sz[sons[now][0]] : 0); if(x == value[now]) {splay(now);return ans + 1;} ans += cnt[now]; now = sons[now][1]; } } } inline int find_pre() { int now = sons[rt][0]; while(sons[now][1]) now = sons[now][1]; return now; } inline int find_suffix() { int now = sons[rt][1]; while(sons[now][0]) now = sons[now][0]; return now; } inline void Delete(int x) { int h = find_rank(x); if(cnt[rt] > 1) {cnt[rt]--;update(rt);return;} if(!sons[rt][0] && !sons[rt][1]) {Clear(rt);rt = 0;return;} if(!sons[rt][0]) { int old_rt = rt; rt = sons[rt][1]; f[rt] = 0; Clear(old_rt); return; } else if(!sons[rt][1]) { int old_rt = rt; rt = sons[rt][0]; f[rt] = 0; Clear(old_rt); return; } int lemx = find_pre(),old_rt = rt; splay(lemx); sons[rt][1] = sons[old_rt][1]; f[sons[old_rt][1]] = rt; Clear(old_rt); update(rt); } map<int,int> mp; void solve() { int n;n = read(); LL ans = 0; value[0] = INF; for(int i = 1;i <= n;++i) { int x;x = read(); insert(x); if(i == 1) ans += x; else { if(mp[x] != 0) continue; int pre = value[find_pre()]; int nxt = value[find_suffix()]; // printf("pre is %d nxt is %d\n",pre,nxt); int ma = min(abs(x - pre),abs(x - nxt)); ans += ma; } mp[x]++; } printf("%lld\n",ans); } int main() { solve(); system("pause"); return 0; }
P3988 [SHOI2013]发牌
模拟之后可以发现,那就是它询问的点一直是询问当前序列里第pre + x小是谁。
那么就是变成了求Kth问题,splay维护一下。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> pii; const int N = 7e5 + 5; const int M = 2e4 + 5; const double eps = 1e-10; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e8 #define dbg(ax) cout << "now this num is " << ax << endl; inline int read() { int f = 1;int x = 0;char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } inline long long ADD(long long x,long long y) {return (x + y) % Mod;} inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;} inline long long MUL(long long x,long long y) {return x * y % Mod;} int f[N],cnt[N],value[N],sons[N][2],sz[N],allsz,rt; //allsz - 下表 inline bool get_which(int x) {return sons[f[x]][1] == x;} inline void update(int x) { if(x) { sz[x] = cnt[x]; if(sons[x][0]) sz[x] += sz[sons[x][0]]; if(sons[x][1]) sz[x] += sz[sons[x][1]]; } return ; } inline void Clear(int x) {sons[x][0] = sons[x][1] = f[x] = sz[x] = cnt[x] = value[x] = 0;} inline void rotate(int x) {//旋转 int fr = f[x],g_fr = f[fr],w_son = get_which(x); sons[fr][w_son] = sons[x][w_son ^ 1]; f[sons[fr][w_son]] = fr; sons[x][w_son ^ 1] = fr; f[fr] = x; f[x] = g_fr; if(g_fr) sons[g_fr][sons[g_fr][1] == fr] = x; update(fr); update(x); } inline void splay(int x) { for(int i;i = f[x];rotate(x)) if(f[i]) rotate((get_which(x) == get_which(i)) ? i : x); rt = x; } inline void insert(int x) { if(!rt) { rt = ++allsz; sons[allsz][0] = sons[allsz][1] = f[allsz] = 0; sz[allsz] = cnt[allsz]++; value[allsz] = x; return ; } int now = rt,fa = 0; while(1) { if(x == value[now]) { cnt[now]++; update(now); update(fa); splay(now); break; } fa = now; now = sons[now][value[now] < x]; if(!now) { f[++allsz] = fa; sons[allsz][0] = sons[allsz][1] = 0; sz[allsz] = cnt[allsz] = 1; sons[fa][value[fa] < x] = allsz; value[allsz] = x; update(fa); splay(allsz); break; } } } inline int find_num(int x) {//查询排名为x的数 int now = rt; while(1) { if(sons[now][0] && x <= sz[sons[now][0]]) now = sons[now][0]; else { int temp = (sons[now][0] ? sz[sons[now][0]] : 0) + cnt[now]; if(x <= temp) return value[now]; x -= temp; now = sons[now][1]; } } } inline int find_rank(int x) {//查询x的排名 int now = rt,ans = 0; while(1) { if(x < value[now]) now = sons[now][0]; else { ans += (sons[now][0] ? sz[sons[now][0]] : 0); if(x == value[now]) {splay(now);return ans + 1;} ans += cnt[now]; now = sons[now][1]; } } } inline int find_pre() { int now = sons[rt][0]; while(sons[now][1]) now = sons[now][1]; return now; } inline int find_suffix() { int now = sons[rt][1]; while(sons[now][0]) now = sons[now][0]; return now; } inline void Delete(int x) { int h = find_rank(x); if(cnt[rt] > 1) {cnt[rt]--;update(rt);return;} if(!sons[rt][0] && !sons[rt][1]) {Clear(rt);rt = 0;return;} if(!sons[rt][0]) { int old_rt = rt; rt = sons[rt][1]; f[rt] = 0; Clear(old_rt); return; } else if(!sons[rt][1]) { int old_rt = rt; rt = sons[rt][0]; f[rt] = 0; Clear(old_rt); return; } int lemx = find_pre(),old_rt = rt; splay(lemx); sons[rt][1] = sons[old_rt][1]; f[sons[old_rt][1]] = rt; Clear(old_rt); update(rt); } void solve() { int n;n = read(); int pre = 0; for(int i = 1;i <= n;++i) insert(i); while(n--) { int x;x = read(); pre += x; pre %= sz[rt]; int ma = find_num(pre + 1); Delete(ma); printf("%d\n",ma); } } int main() { solve(); system("pause"); return 0; }
SP1716 GSS3 - Can you answer these queries III
这里的核心问题就是区间最大子段和的问题。
我们进行分类讨论:分成跨越和不跨越的情况。
一开始还想得维护左右一直最大的子段的距离的,但是其实不用维护,如果跨越了那就两种:
1: 加上整段,2:加上边界开始的最大。
这里直接线段树就可以了。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> pii; const int N = 1e5 + 5; const int M = 2e5 + 5; const double eps = 1e-10; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; inline int read() { int f = 1;int x = 0;char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } inline long long ADD(long long x,long long y) {return (x + y) % Mod;} inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;} inline long long MUL(long long x,long long y) {return x * y % Mod;} int a[N]; LL mx[M << 2],le[M << 2],ri[M << 2],sum[M << 2]; struct Node{LL le,ri,sum,mx;}; void Pushup(int idx) { mx[idx] = max(mx[idx << 1],mx[idx << 1 | 1]); mx[idx] = max(mx[idx],ri[idx << 1] + le[idx << 1 | 1]); sum[idx] = sum[idx << 1] + sum[idx << 1 | 1]; le[idx] = max(le[idx << 1],sum[idx << 1] + le[idx << 1 | 1]); ri[idx] = max(ri[idx << 1 | 1],sum[idx << 1 | 1] + ri[idx << 1]); } void update(int L,int r,int x,int val,int idx) { if(L == r) { mx[idx] = le[idx] = ri[idx] = sum[idx] = val; return ; } int mid = (L + r) >> 1; if(mid >= x) update(L,mid,x,val,idx << 1); else update(mid + 1,r,x,val,idx << 1 | 1); Pushup(idx); } Node query(int L,int r,int ll,int rr,int idx) { if(L >= ll && r <= rr) { return Node{le[idx],ri[idx],sum[idx],mx[idx]}; } int mid = (L + r) >> 1; LL ma = -INF; Node ans = {ma,ma,ma,ma}; if(mid >= ll && mid < rr) { Node a = query(L,mid,ll,rr,idx << 1); Node b = query(mid + 1,r,ll,rr,idx << 1 | 1); ans.mx = max(a.mx,b.mx); ans.mx = max(ans.mx,a.ri + b.le); ans.sum = a.sum + b.sum; ans.le = max(a.le,a.sum + b.le); ans.ri = max(b.ri,b.sum + a.ri); return ans; } else if(mid >= ll) ans = query(L,mid,ll,rr,idx << 1); else if(mid < rr) ans = query(mid + 1,r,ll,rr,idx << 1 | 1); return ans; } void solve() { int n;n = read(); for(int i = 1;i <= n;++i) { a[i] = read(); update(1,5e4,i,a[i],1); } int m;m = read(); while(m--) { int id,x,y;id = read(),x = read(),y = read(); if(id == 0) update(1,5e4,x,y,1); else printf("%lld\n",query(1,5e4,x,y,1).mx); } } int main() { solve(); system("pause"); return 0; }
SP4487 GSS6 - Can you answer these queries VI
这里就在上面的题多了插入和修改。但是因为他插入后可能会改变每个位置的值,所以线段树就无法维护了。
而且线段树还多了logn的常数,甚至T了。
当我在郁闷地调试splay的时候,FHQtheap出现了。
FHQtheap:无旋theap,不像splay平衡树一样依靠旋转来维护平衡,而是通过split和merge(分裂和合并)来维护堆性质。
然后就可以做了:
注意mx[0]要赋值为无穷小因为没有节点就用0代表。
and这里其实不用卡常数,只是读入被卡了,据我观察1e5量级下scanf比read还是要快挺多的。
这里read就被卡超时了,然后scanf过了。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 2e4 + 5; const double eps = 1e-10; const LL Mod = 1e9 + 7; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; inline int read() { int f = 1,x = 0;char c = getchar(); while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } inline long long ADD(long long x,long long y) {return (x + y) % Mod;} inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;} inline long long MUL(long long x,long long y) {return x * y % Mod;} int val[N],sons[N][2],sz[N],pri[N],allsz = 0; int mx[N],le[N],ri[N],sum[N]; inline void Pushup(int x) { sz[x] = sz[sons[x][0]] + sz[sons[x][1]] + 1; sum[x] = sum[sons[x][0]] + sum[sons[x][1]] + val[x]; mx[x] = max(mx[sons[x][0]],mx[sons[x][1]]); mx[x] = max(mx[x],ri[sons[x][0]] + val[x] + le[sons[x][1]]); le[x] = max(le[sons[x][0]],sum[sons[x][0]] + val[x] + le[sons[x][1]]); ri[x] = max(ri[sons[x][1]],sum[sons[x][1]] + val[x] + ri[sons[x][0]]); } inline int new_node(int x) { sz[++allsz] = 1; val[allsz] = sum[allsz] = mx[allsz] = x; le[allsz] = ri[allsz] = max(x,0); pri[allsz] = rand(); return allsz; } inline void split(int now,int k,int &x,int &y) { if(!now) x = y = 0; else { if(k <= sz[sons[now][0]]) y = now,split(sons[now][0],k,x,sons[now][0]); else x = now,split(sons[now][1],k - sz[sons[now][0]] - 1,sons[now][1],y); Pushup(now); } } inline int merge(int x,int y) { if(!x || !y) return x + y; if(pri[x] < pri[y]) { sons[x][1] = merge(sons[x][1],y); Pushup(x); return x; } else { sons[y][0] = merge(x,sons[y][0]); Pushup(y); return y; } } void solve() { int n;scanf("%d",&n); int rt = 0,x = 0,y = 0,z = 0; for(int i = 1;i <= n;++i) { int v;scanf("%d",&v); rt = merge(rt,new_node(v)); } mx[0] = -1e9; int m;scanf("%d",&m); while(m--) { char c[2];scanf("%s",c); if(c[0] == 'I') { int L,r;scanf("%d %d",&L,&r); split(rt,L - 1,x,y); rt = merge(x,merge(new_node(r),y)); } else if(c[0] == 'D') { int L;scanf("%d",&L); split(rt,L - 1,x,y); split(y,1,y,z); rt = merge(x,z); } else if(c[0] == 'R') { int L,r;scanf("%d %d",&L,&r); split(rt,L - 1,x,y); split(y,1,y,z); val[y] = r; Pushup(y); rt = merge(x,merge(y,z)); } else { int L,r;scanf("%d %d",&L,&r); split(rt,r,x,y); split(x,L - 1,x,z); printf("%d\n",mx[z]); rt = merge(x,merge(z,y)); } } } int main() { solve(); // system("pause"); return 0; }
https://codeforces.com/problemset/problem/600/E:
$dsu on tree维护一个val,对于最大的次数,考虑和之前做过的差不多的经典莫队来维护(也就是最大值的连续性)$
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double ld; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 5e6 + 5; const LL Mod = 1e9 + 7; #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,c[N],Son,son[N],sz[N]; vector<int> G[N]; void dfs(int u,int fa) { sz[u] = 1; for(auto v : G[u]) { if(v == fa) continue; dfs(v,u); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; } } int cnt[N],ct[N],mx = 0; LL val[N],ans[N]; void modify(int u,int fa,int id) { if(id == 1) { ct[cnt[c[u]]]--; val[cnt[c[u]]] -= c[u]; ct[++cnt[c[u]]]++; val[cnt[c[u]]] += c[u]; mx = max(mx,cnt[c[u]]); } else { if(ct[cnt[c[u]]] == 1 && mx == cnt[c[u]]) mx--; ct[cnt[c[u]]]--; val[cnt[c[u]]] -= c[u]; ct[--cnt[c[u]]]++; val[cnt[c[u]]] += c[u]; } for(auto v : G[u]) { if(v == fa || v == Son) continue; modify(v,u,id); } } void dsu(int u,int fa,int op) { for(auto v : G[u]) { if(v == fa || v == son[u]) continue; dsu(v,u,0); } if(son[u]) dsu(son[u],u,1),Son = son[u]; ct[cnt[c[u]]]--; val[cnt[c[u]]] -= c[u]; ct[++cnt[c[u]]]++; val[cnt[c[u]]] += c[u]; mx = max(mx,cnt[c[u]]); for(auto v : G[u]) { if(v == fa || v == son[u]) continue; modify(v,u,1); } ans[u] = val[mx]; Son = 0; if(op == 0) modify(u,fa,-1); } void solve() { scanf("%d",&n); for(int i = 1;i <= n;++i) scanf("%d",&c[i]); for(int i = 1;i < n;++i) { int x,y;scanf("%d %d",&x,&y); G[x].push_back(y); G[y].push_back(x); } dfs(1,0); dsu(1,0,0); for(int i = 1;i <= n;++i) printf("%lld ",ans[i]); } int main() { //int _; //for(scanf("%d",&_);_;_--) solve(); system("pause"); return 0; }
https://ac.nowcoder.com/acm/contest/4010/E:
复杂度有点难估计,一开始以为是nlognlogn。其实并不是,以为这里的set大小是在动态变化,所以复杂度应该要减少一个常数,所以能过。
维护就比较简单了,加入一个数和删去一个数的时候都维护一下贡献就行了。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double ld; typedef pair<int,int> pii; const int N = 2e5 + 5; const int M = 5e6 + 5; const LL Mod = 1e9 + 7; #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; inline long long ADD(long long x,long long y) { if(x + y < 0) return ((x + y) % Mod + Mod) % Mod; return (x + y) % Mod; } inline long long MUL(long long x,long long y) { if(x * y < 0) return ((x * y) % Mod + Mod) % Mod; return x * y % Mod; } inline long long DEC(long long x,long long y) { if(x - y < 0) return (x - y + Mod) % Mod; return (x - y) % Mod; } int n,x,sz[N],son[N],Son; LL ans = 0,sum[N]; vector<int> G[N]; set<int> s; void dfs(int u,int fa) { sz[u] = 1; for(auto v : G[u]) { dfs(v,u); sz[u] += sz[v]; if(sz[son[u]] < sz[v]) son[u] = v; } } void del(LL x,LL y) { ans -= (y - x) * (y - x); } void add(LL x,LL y) { ans += (y - x) * (y - x); } void cal(int u,int id) { if(id == 1) { int L = -1,r = -1; auto it = s.lower_bound(u); if(s.size() > 0 && *(--s.end()) > u) r = *it; if(it != s.begin()) L = *(--it); if(L != -1 && r != -1) del(L,r); if(L != -1) add(L,u); if(r != -1) add(u,r); s.insert(u); } else { int L = -1,r = -1; auto it = s.lower_bound(u); if(s.size() && *(--s.end()) > u) r = *(++it),--it; if(it != s.begin()) L = *(--it); if(L != -1 && r != -1) add(L,r); if(L != -1) del(L,u); if(r != -1) del(u,r); s.erase(u); } for(auto v : G[u]) { if(v == Son) continue; cal(v,id); } } void dsu(int u,int op) { for(auto v : G[u]) { if(v == son[u]) continue; dsu(v,0); } if(son[u]) dsu(son[u],1),Son = son[u]; int L = -1,r = -1; auto it = s.lower_bound(u); if(s.size() > 0 && *(--s.end()) > u) r = *it; if(it != s.begin()) L = *(--it); if(L != -1 && r != -1) del(L,r); if(L != -1) add(L,u); if(r != -1) add(u,r); s.insert(u); for(auto v : G[u]) { if(v == son[u]) continue; cal(v,1); } Son = 0; sum[u] = ans; if(op == 0) cal(u,-1); } void solve() { scanf("%d",&n); for(int i = 2;i <= n;++i) scanf("%d",&x),G[x].push_back(i); dfs(1,0); dsu(1,0); for(int i = 1;i <= n;++i) printf("%lld\n",sum[i]); } int main() { //int _; //for(scanf("%d",&_);_;_--) solve(); system("pause"); return 0; } /* 10 1 1 2 2 3 3 4 4 5 */

浙公网安备 33010602011771号