主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )
在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 【模板】可持久化线段树 1(主席树)就突然有了不详的预感2333
果然。。。然后我gg了!被大佬虐了!
题意就不写了,太经典了(可我还是不会这题,我太菜了)
大佬的题解写的太神仙了,我这么菜的人都看懂了2333,所以我就不写了。。。
不过这题是真的坑啊。。。老师在上面讲的时候,我们开始提交(他们交主席树,我交整体二分)然后等讲完我们还没过23333
MLE、TLE、WA(可能还有CE)轮着错QWQ真是可怕
#ifndef _GLIBCXX_NO_ASSERT #include <cassert> #endif #include <cctype> #include <cerrno> #include <cfloat> #include <ciso646> #include <climits> #include <clocale> #include <cmath> #include <csetjmp> #include <csignal> #include <cstdarg> #include <cstddef> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #if __cplusplus >= 201103L #include <ccomplex> #include <cfenv> #include <cinttypes> #include <cstdalign> #include <cstdbool> #include <cstdint> #include <ctgmath> #include <cwchar> #include <cwctype> #endif // C++ #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <exception> #include <fstream> #include <functional> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <locale> #include <map> #include <memory> #include <new> #include <numeric> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <typeinfo> #include <utility> #include <valarray> #include <vector> #if __cplusplus >= 201103L #include <array> #include <atomic> #include <chrono> #include <condition_variable> #include <forward_list> #include <future> #include <initializer_list> #include <mutex> #include <random> #include <ratio> #include <regex> #include <scoped_allocator> #include <system_error> #include <thread> #include <tuple> #include <typeindex> #include <type_traits> #include <unordered_map> #include <unordered_set> #endif #define MAXN 100010 using namespace std; int n,q,x,y,z,m,tw,c[MAXN],a[MAXN],b[MAXN],l[2500010],r[2500010]; int cnt,sum[2500010],T; inline int read() { char ch; bool f=false; int res=0; while (((ch=getchar())<'0'||ch>'9')&&ch!='-'); if (ch=='-') f=true; else res=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') res=(res<<3)+(res<<1)+ch-'0'; return f?~res+1:res; } inline int build(int x,int y){ int tt=cnt++; sum[tt]=0; int mid=(x+y)>>1; if (x<y){ l[tt]=build(x,mid); r[tt]=build(mid+1,y); } //c[0]=cnt; return tt; } inline int add(int k,int t,int w,int x){ int tt=++cnt; l[tt]=l[k],r[tt]=r[k],sum[tt]=sum[k]+1; int mid=(t+w)>>1; if (t<w&&x<=mid) l[tt]=add(l[k],t,mid,x); else if(t<w&&x>mid) r[tt]=add(r[k],mid+1,w,x); return tt; } inline int ask(int u,int v, int t,int w,int k){ if (t>=w) return t; int mid=(t+w)>>1; int x=sum[l[v]]-sum[l[u]]; if (x>=k) return ask(l[u],l[v],t,mid,k); else return ask(r[u],r[v],mid+1,w,k-x); } int main(){ T=read(); while (T--){ cnt=0; memset(c,0,sizeof(c)); memset(r,0,sizeof(r)); memset(l,0,sizeof(l)); n=read(),q=read(); for (int i=1;i<=n;++i) b[i]=a[i]=read(); sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1; //build(1,m); c[0]=build(1,m); for (int i=1;i<=n;++i){ tw=lower_bound(b+1,b+1+m,a[i])-b; c[i]=add(c[i-1],1,m,tw); } for (int i=1;i<=q;++i){ x=read(),y=read(),z=read(); printf("%d\n",b[ask(c[x-1],c[y],1,m,z)]); } } return 0; }
Description
给你一棵有n个结点的树,节点编号为1~n。每个节点都有一个权值。求从节点u到节点v的第k小权值。
Solution
主席树中每一棵线段树维护一个前缀的答案。
对于每一组询问(u,v,k),令z = lca(x, y)。
则(x,y)这条路径上的答案就可以拆成root[x] + root[y] - root[z] - root[fa(z)]
#ifndef _GLIBCXX_NO_ASSERT #include <cassert> #endif #include <cctype> #include <cerrno> #include <cfloat> #include <ciso646> #include <climits> #include <clocale> #include <cmath> #include <csetjmp> #include <csignal> #include <cstdarg> #include <cstddef> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #if __cplusplus >= 201103L #include <ccomplex> #include <cfenv> #include <cinttypes> #include <cstdalign> #include <cstdbool> #include <cstdint> #include <ctgmath> #include <cwchar> #include <cwctype> #endif // C++ #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <exception> #include <fstream> #include <functional> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <locale> #include <map> #include <memory> #include <new> #include <numeric> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <typeinfo> #include <utility> #include <valarray> #include <vector> #if __cplusplus >= 201103L #include <array> #include <atomic> #include <chrono> #include <condition_variable> #include <forward_list> #include <future> #include <initializer_list> #include <mutex> #include <random> #include <ratio> #include <regex> #include <scoped_allocator> #include <system_error> #include <thread> #include <tuple> #include <typeindex> #include <type_traits> #include <unordered_map> #include <unordered_set> #endif #define MAXN 100010 using namespace std; int first[MAXN*2],to[MAXN*2],nxt[MAXN*2],lca,z,k,x,y; int t[MAXN],f[MAXN][25],b[MAXN],n,m; int depth[MAXN],cnt; int l[MAXN<<5],r[MAXN<<5],sum[MAXN<<5],X; struct Node{ int a,b,c; }a[MAXN]; inline int read() { char ch; bool f=false; int res=0; while (((ch=getchar())<'0'||ch>'9')&&ch!='-'); if (ch=='-') f=true; else res=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') res=(res<<3)+(res<<1)+ch-'0'; return f?~res+1:res; } inline bool cmp(const Node& a,const Node& b){ return a.a<b.a; } inline bool cmp1(const Node &a,const Node& b){ return a.c<b.c; } inline void add(int x,int y){ cnt++; to[cnt]=y,nxt[cnt]=first[x],first[x]=cnt; cnt++; to[cnt]=x,nxt[cnt]=first[y],first[y]=cnt; } inline int Build(int k,int t,int w,int x){ int tt=++X; l[tt]=l[k],r[tt]=r[k],sum[tt]=sum[k]+1; int mid=(t+w)>>1; if (t<w&&x<=mid) l[tt]=Build(l[k],t,mid,x); else if(t<w&&x>mid) r[tt]=Build(r[k],mid+1,w,x); //printf("%d\n",tt); return tt; } inline int ask(int u,int v,int x1,int y1,int t,int w,int k){ if (t>=w) return b[t]; int mid=(t+w)>>1; int x=sum[l[u]]+sum[l[v]]-sum[l[x1]]-sum[l[y1]]; //printf("%d\n",x); if (x>=k) return ask(l[u],l[v],l[x1],l[y1],t,mid,k); else return ask(r[u],r[v],r[x1],r[y1],mid+1,w,k-x); } void dfs(int x,int fa,int y){ depth[x]=y; f[x][0]=fa; for (int i=1;(1<<i)<=y;++i) f[x][i]=f[f[x][i-1]][i-1]; for (int i=first[x];i;i=nxt[i]){ if (to[i]==fa) continue; int z=to[i]; t[z]=Build(t[x],1,n,a[z].b); dfs(z,x,y+1); } } inline int Lca(int a,int b){ if (depth[a]<depth[b]){ int t=a; a=b,b=t; } for (int i=20;i>=0;--i){ if (depth[a]-(1<<i)<depth[b]) continue; a=f[a][i]; } if (a==b) return a; for (int i=20;i>=0;--i){ if (f[a][i]==f[b][i]) continue; a=f[a][i]; b=f[b][i]; } return f[a][0]; } int main(){ n=read(),m=read(); for (int i=1;i<=n;++i) a[i].a=read(),a[i].c=i; sort(a+1,a+n+1,cmp); for (int i=1;i<=n;++i) if (i!=1&&a[i].a==a[i-1].a) a[i].b=a[i-1].b; else a[i].b=i; sort(a+1,a+n+1,cmp1); for (int i=1;i<=n;++i) b[a[i].b]=a[i].a; for (int i=1;i<n;++i) add(read(),read()); t[1]=Build(0,1,n,a[1].b); dfs(1,0,1); for (int i=1;i<=m;++i){ x=read(),y=read(),k=read(); lca=Lca(x,y); z=ask(t[x],t[y],t[lca],t[f[lca][0]],1,n,k); printf("%d\n",z); } return 0; }
ZOJ 2112 Dynamic Rankings
没错,这就是跟整体二分的题重了2333
所以我打算贺一波
#include <algorithm> #include <bitset> #include <complex> #include<cstring> #include <deque> #include <exception> #include <fstream> #include <functional> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <locale> #include <map> #include <memory> #include <new> #include <numeric> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <typeinfo> #include <utility> #include <valarray> #include <vector> #if __cplusplus >= 201103L #include <array> #include <atomic> #include <chrono> #include <condition_variable> #include <forward_list> #include <future> #include <initializer_list> #include <mutex> #include <random> #include <ratio> #include <regex> #include <scoped_allocator> #include <system_error> #include <thread> #include <tuple> #include <typeindex> #include <type_traits> #include <unordered_map> #include <unordered_set> #endif #define INF 1000000007 #define MAXN 2000010 using namespace std; struct Node { int x,y,a,b,c; }q[MAXN],a[MAXN],b[MAXN]; int t[MAXN],ans[MAXN],n,m,x,y,z,cnt,k; int aa[MAXN]; char ch; int ansn; inline int read() { char ch; bool f=false; int res=0; while (((ch=getchar())<'0'||ch>'9')&&ch!='-'); if (ch=='-') f=true; else res=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') res=(res<<3)+(res<<1)+ch-'0'; return f?~res+1:res; } inline int lowbit(int x) { return x&(-x); } inline void add(int x,int y) { while (x<=n) { t[x]+=y,x+=lowbit(x); } } inline int sum(int x) { int summ=0; while (x>0) { summ+=t[x],x-=lowbit(x); } return summ; } inline void Build(int x,int i) { cnt++; q[cnt].x=x,q[cnt].b=1,q[cnt].c=i; } inline void Build1(int x,int y,int k,int i) { cnt++,ansn++; q[cnt].x=x,q[cnt].y=y,q[cnt].a=k,q[cnt].b=0,q[cnt].c=ansn; } inline void Build2(int x,int y,int i) { cnt++; q[cnt].x=aa[x],q[cnt].b=-1,q[cnt].c=x; } inline void Build3(int x,int y,int i) { cnt++; q[cnt].x=aa[x],q[cnt].b=1,q[cnt].c=x; } void sc(int t,int w,int l,int r) { if (t>w) return; if (l==r) { for (int i=t;i<=w;++i) if (q[i].b==0) ans[q[i].c]=l; return; } int mid=(l+r)>>1,t1=0,w1=0; for (int i=t;i<=w;++i) if (q[i].b) { if (q[i].x<=mid) /*add(q[i].c,1),*/add(q[i].c,q[i].b),a[++t1]=q[i]; else b[++w1]=q[i]; } else { int tw=sum(q[i].y)-sum(q[i].x-1); if (tw>=q[i].a) a[++t1]=q[i]; else { q[i].a=q[i].a-tw; b[++w1]=q[i]; } } for (int i=1;i<=t1;++i) if (a[i].b) add(a[i].c,-a[i].b); for (int i=1;i<=t1;++i) q[t+i-1]=a[i]; /*for (int i=1;i<=t1;++i) printf("%d %d %d %d %d ",a[i].x,a[i].y,a[i].a,a[i].b,a[i].c); printf("\n");*/ for (int i=1;i<=w1;++i) q[t+t1+i-1]=b[i]; sc(t,t+t1-1,l,mid); sc(t+t1,w,mid+1,r); } int main() { int T=read(); while (T--){ memset(q,0,sizeof q); memset(a,0,sizeof a); memset(b,0,sizeof b); memset(ans,0,sizeof ans); n=read(),m=read(),cnt=0,ansn=0; for (int i=1;i<=n;++i) { aa[i]=read(); Build(aa[i],i); } for (int i=1;i<=m;++i) { /*scanf("%c",&ch);*/cin>>ch;x=read(),y=read(); if (ch=='Q'){ k=read(); Build1(x,y,k,i); } else { Build2(x,y,i); aa[x]=y; Build3(x,y,i); } } //for (int i=1;i<=cnt;++i) // printf("%d %d %d %d %d\n",q[i].x,q[i].y,q[i].a,q[i].b,q[i].c); sc(1,cnt,-INF,INF); for (int i=1;i<=ansn;++i) printf("%d\n",ans[i]); } return 0; }
这大概是最容易过的一题吧QWQ
Description
给出一个序列,q次询问从l到r中出现的数字出现次数和k取最小值后的和
Solution
Every time we process a plan, let's count only the first k warriors of some type.
When will the warrior on position i be counted? Of course, he has to be present in the plan, so l ≤ i ≤ r. But also he has to be among kfirst warriors of his type in this plan.
Let's denote a function prev(x, y):
- prev(x, 1) is the position of previous warrior of the same type before warrior x (that is, the greatest i such that i < x and ai = ax). If there's no any, then prev(x, 1) = - 1;
- prev(x, y) = prev(prev(x, 1), y - 1)) if y > 1.
It is easy to prove that the warrior x will be among k first warriors in some plan iff l > prev(x, k) and x ≤ r.
So we can make a new array b: bi = prev(i, k). Then we build a segment tree on this array. The node of the segment tree will store all values of bi from the segment corresponding to this node (in sorted order). Then to get answer to the plan, we have to count the number of elements on segment [l, r] that are less than l.
Complexity is , or if you use fractional cascading technique.
//官方题解
简单粗暴的说就是如果一个数被选,则和它相等的数,在它前面的第K的位置应该小于l,按照前面第K个数的位置插入主席树
#include <bits/stdc++.h> #define MAXN 100001 using namespace std; int n,k,x,y,q,cnt,t1[MAXN*22],l[MAXN*22],r[MAXN*22],q1[MAXN],fa[MAXN],w1; map <int, vector <int> > ma; vector <int> a; inline int read() { char ch; bool f=false; int res=0; while (((ch=getchar())<'0'||ch>'9')&&ch!='-'); if (ch=='-') f=true; else res=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') res=(res<<3)+(res<<1)+ch-'0'; return f?~res+1:res; } void Build(int t,int w,int k){ if (t==w){ t1[k]=1; return; } l[k]=cnt++; r[k]=cnt++; int mid=(t+w)>>1; Build (t,mid,l[k]); Build(mid+1,w,r[k]); t1[k]=t1[l[k]]+t1[r[k]]; } void add(int t,int w,int k,int k1,int x,int val){ t1[k]=t1[k1]; if(t==w){ t1[k]=val; return; } int mid=(t+w)>>1; if(x<=mid){ r[k]=r[k1]; l[k]=cnt++; add(t,mid,l[k],l[k1],x,val); } else{ l[k]=l[k1]; r[k]=cnt++; add(mid+1,w,r[k],r[k1],x,val); } t1[k]=t1[l[k]]+t1[r[k]]; } int ask(int t,int w,int k,int x,int y){ if (w<x) return 0; if (t>y) return 0; if (x<=t&&w<=y) return t1[k]; int mid=(t+w)>>1; return ask(t,mid,l[k],x,y)+ask(mid+1,w,r[k],x,y); } int main() { a.push_back(0); n=read(),k=read(); for (int i=1;i<=n;++i) a.push_back(read()); for (int i=1;i<=n;++i){ vector <int> &c=ma[a[i]]; c.push_back(i); q1[i]=(c.size()<=k?-1:c[c.size()-k-1]); } fa[0]=cnt++; Build(1,n,fa[0]); for (int i=1;i<=n;++i){ fa[i]=cnt++; if (q1[i]==-1) add(1,n,fa[i],fa[i-1],i,1); else add(1,n,fa[i],fa[i-1],q1[i],0); } q=read(); while (q--){ x=read(),y=read(); x=(x+w1)%n+1; y=(y+w1)%n+1; if (y<x) swap(x,y); w1=ask(1,n,fa[y],x,y); printf("%d\n",w1); } return 0; }
Description
给定n个点m条边的有向图,可能不连通,可能有重边,也可能会有自环。求最长路径。
Solution
STL乱搞
#include<bits/stdc++.h> using namespace std; inline int read() { char ch; bool f=false; int res=0; while (((ch=getchar())<'0'||ch>'9')&&ch!='-'); if (ch=='-') f=true; else res=ch-'0'; while ((ch=getchar())>='0'&&ch<='9') res=(res<<3)+(res<<1)+ch-'0'; return f?~res+1:res; } map<int,int> mp[100009]; map<int,int>::iterator z,x; int n,m,a,b,w,c,ans; int main() { n=read(),m=read(); for (int i=1;i<=m;++i){ a=read(),b=read(),w=read(); z=mp[a].lower_bound(w); if (z==mp[a].begin()) a=1; else a=1+(--z)->second; z=mp[b].upper_bound(w); if (z==mp[b].begin()) c=0; else c=(--z)->second; if (c<a){ mp[b][w]=max(mp[b][w],a); ans=max(ans,mp[b][w]),z=mp[b].upper_bound(w); while (!(z==mp[b].end()||z->second>a)) x=z++,mp[b].erase(x); } } printf("%d\n",ans); return 0; }