这个题……感觉离线和在线的代码难度差不多(pb_ds不要说话)。
离线的话,就是把所有询问按照w排个序,然后一边Kruskal+平衡树启发式合并一边回答询问就好了。
在线也不难写。首先Kruskal重构树(这个Kruskal重构树是不按秩合并还要添虚点的那种……),那么每个点可以到达的点一定在某个子树里。子树的dfs序是连续的,所以可以对dfs序建主席树来求区间k大。又因为只有叶子节点的点权是有意义的,所以可以只对叶子的dfs序建主席树。查询的时候倍增跳到最高的w<=询问的w的点然后主席树就好了。
其实树剖跳父亲也可以,先跳整条链,整条链跳不动的时候就在最后一条链上二分,也是O(logn)的。不过可能是太弱,二分写挂了,结果WA到死……无奈用倍增重写了一遍。
限时20s,结果我跑了19.8s,这速度真是感人肺腑……
还有,copy的那个a一开始忘了+1了,调了一节课,虚死……
1 /************************************************************** 2 Problem: 3551 3 User: hzoier 4 Language: C++ 5 Result: Accepted 6 Time:19800 ms 7 Memory:114432 kb 8 ****************************************************************/ 9 #include<cstdio> 10 #include<cstring> 11 #include<algorithm> 12 using namespace std; 13 const int maxn=200010,maxe=500010; 14 struct edge{ 15 int from,to,w; 16 bool operator<(const edge &e)const{return w<e.w;} 17 }e[maxe+maxn]; 18 void Kruskal(); 19 int findroot(int); 20 void mergeset(int,int); 21 void dfs(int); 22 void build(int,int,int&,int); 23 void query(int,int,int,int); 24 int sm[maxn<<5],lc[maxn<<5],rc[maxn<<5],root[maxn],tree_cnt=0; 25 int n,M=0,m,q,h[maxn],a[maxn],cnt,prt[maxn],w[maxn],f[maxn][20],ch[maxn][2],L[maxn],R[maxn],pr=0,x,d,k,ans; 26 int main(){ 27 scanf("%d%d%d",&n,&m,&q); 28 while((1<<M)<(n<<1))M++; 29 for(int i=1;i<=n;i++)scanf("%d",&h[i]); 30 copy(h+1,h+n+1,a+1); 31 sort(a+1,a+n+1); 32 for(int i=1;i<=n;i++)h[i]=lower_bound(a+1,a+n+1,h[i])-a; 33 for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w); 34 for(int i=2;i<=n;i++){ 35 e[++m].from=1; 36 e[m].to=i; 37 e[m].w=~(1<<31); 38 } 39 cnt=n; 40 Kruskal(); 41 dfs(cnt); 42 for(int j=1;j<=M;j++)for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1]; 43 while(q--){ 44 scanf("%d%d%d",&x,&d,&k); 45 if(ans!=-1){x^=ans;d^=ans;k^=ans;} 46 for(int j=M;j!=-1;j--)if(f[x][j]&&w[f[x][j]]<=d)x=f[x][j]; 47 query(1,n,root[R[x]],root[L[x]-1]); 48 printf("%d\n",ans); 49 } 50 return 0; 51 } 52 void Kruskal(){ 53 for(int i=1;i<=n;i++)prt[i]=i; 54 stable_sort(e+1,e+m+1); 55 for(int i=1;i<=m;i++)if(findroot(e[i].from)!=findroot(e[i].to)){ 56 cnt++; 57 prt[cnt]=cnt; 58 w[cnt]=e[i].w; 59 ch[cnt][0]=findroot(e[i].from); 60 ch[cnt][1]=findroot(e[i].to); 61 mergeset(e[i].from,cnt); 62 mergeset(e[i].to,cnt); 63 } 64 } 65 int findroot(int x){return prt[x]==x?x:(prt[x]=findroot(prt[x]));} 66 void mergeset(int x,int y){prt[findroot(x)]=findroot(y);} 67 void dfs(int x){ 68 if(ch[x][0]){ 69 f[ch[x][0]][0]=f[ch[x][1]][0]=x; 70 dfs(ch[x][0]); 71 dfs(ch[x][1]); 72 L[x]=L[ch[x][0]]; 73 R[x]=R[ch[x][1]]; 74 } 75 else{ 76 k=h[x]; 77 build(1,n,root[pr+1],root[pr]); 78 L[x]=R[x]=++pr; 79 } 80 } 81 void build(int l,int r,int &rt,int pr){ 82 sm[rt=++tree_cnt]=sm[pr]+1; 83 if(l==r)return; 84 lc[rt]=lc[pr];rc[rt]=rc[pr]; 85 int mid=(l+r)>>1; 86 if(k<=mid)build(l,mid,lc[rt],lc[pr]); 87 else build(mid+1,r,rc[rt],rc[pr]); 88 } 89 void query(int l,int r,int rt,int pr){ 90 if(sm[rt]-sm[pr]<k){ 91 ans=-1; 92 return; 93 } 94 if(l==r){ 95 ans=a[l]; 96 return; 97 } 98 int mid=(l+r)>>1; 99 if(k<=sm[rc[rt]]-sm[rc[pr]])query(mid+1,r,rc[rt],rc[pr]); 100 else{ 101 k-=sm[rc[rt]]-sm[rc[pr]]; 102 query(l,mid,lc[rt],lc[pr]); 103 } 104 }
尽头和开端,总有一个在等你。