BZOJ 4336 骑士的旅行 发表于 2017-04-04 | 更新于 2018-06-18 LinkSolution想了一种可持久化可并堆的做法,感觉空间要炸 再仔细想想: 1≤K≤201\le K\le 201≤K≤20MDZZ!! Code123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229#include "lucida"using std::swap;const int MAXN=40000+11,MAXV=1000,MAXLOG=20;int log_2[MAXN<<1];struct _{_(){ log_2[0]=-1; for(int i=1;i<(MAXN<<1);++i) { log_2[i]=log_2[i>>1]+1; }}}Auto;struct Edge { int to;Edge *pre; Edge(int to,Edge *pre):to(to),pre(pre) {} void *operator new(size_t) { static Edge *Me=alloc(Edge,MAXN<<1); return Me++; }}*G[MAXN];void Adde(int f,int t) { G[f]=new Edge(t,G[f]); G[t]=new Edge(f,G[t]);}int force[MAXN],place[MAXN];namespace segtree { const int SIZE=MAXN*MAXLOG*MAXLOG; struct Node *null; struct Node { Node *son[2]; int cnt; Node():cnt(0) { son[0]=son[1]=null; } void *operator new(size_t) { static Node *Me=alloc(Node,SIZE); return Me++; } void Up() { cnt=son[0]->cnt+son[1]->cnt; } }*_null=null=new Node,*_null_son=null->son[0]=null->son[1]=null; class SegTree { public: typedef Node *Iter; Node *root; SegTree() {} SegTree(int L,int R):root(null),L(L),R(R) {} void Add(int pos,int v) { Edit(root,L,R,pos,v); } private: int L,R; void Edit(Node *&pos,int L,int R,int goal,int v) { pos=pos==null?new Node:pos; if(L==R) { pos->cnt+=v; } else { int Mid=(L+R)>>1; goal<=Mid?Edit(pos->son[0],L,Mid,goal,v):Edit(pos->son[1],Mid+1,R,goal,v); pos->Up(); } } };}using segtree::SegTree;int stdfs[MAXN<<1],stdc,stdfn[MAXN],st[MAXLOG][MAXN<<1],dep[MAXN],fa[MAXN],lbd[MAXN],rbd[MAXN],dfs[MAXN],dc;void ST() { for(int i=1;i<=stdc;++i) { st[0][i]=stdfs[i]; } for(int lg=1;lg<=log_2[stdc];++lg) { for(int i=1;i<=stdc-(1<<lg)+1;++i) { int pl=st[lg-1][i],pr=st[lg-1][i+(1<<(lg-1))]; st[lg][i]=dep[pl]<dep[pr]?pl:pr; } }}int LCA(int p1,int p2) { p1=stdfn[p1],p2=stdfn[p2]; if(p1>p2) { swap(p1,p2); } int lg=log_2[p2-p1+1],pl=st[lg][p1],pr=st[lg][p2-(1<<lg)+1]; return dep[pl]<dep[pr]?pl:pr;}void DFS(int pos) { stdfs[stdfn[pos]=++stdc]=pos; dfs[lbd[pos]=++dc]=pos; for(Edge *e=G[pos];e;e=e->pre) if(e->to!=fa[pos]) { int u=e->to; fa[u]=pos; dep[u]=dep[pos]+1; DFS(u); stdfs[++stdc]=pos; } rbd[pos]=dc;}class Bit {public: Bit() {} Bit(int n):seg(alloc(SegTree,n+1)),n(n) { for(int i=0;i<=n;++i) { new(&seg[i]) SegTree(1,MAXV); } } int Kiss(int p1,int p2,int K) { static SegTree::Iter plus[MAXN],minus[MAXN]; int lca=LCA(p1,p2); int plc=FindNode(lbd[p1],plus); plc+=FindNode(lbd[p2],plus+plc); int mnc=FindNode(lbd[lca],minus); mnc+=FindNode(lbd[fa[lca]],minus+mnc); int tol=0; for(int i=1;i<=plc;++i) { tol+=plus[i]->cnt; } for(int i=1;i<=mnc;++i) { tol-=minus[i]->cnt; } if(tol<K) { return -1; } int L=1,R=MAXV;//1. while(L!=R) { int tol=0; for(int i=1;i<=plc;++i) { tol+=plus[i]->son[1]->cnt; } for(int i=1;i<=mnc;++i) { tol-=minus[i]->son[1]->cnt; } int dir=K<=tol; for(int i=1;i<=plc;++i) { plus[i]=plus[i]->son[dir]; } for(int i=1;i<=mnc;++i) { minus[i]=minus[i]->son[dir]; } int Mid=(L+R)>>1; if(K<=tol) { L=Mid+1; } else { R=Mid; K-=tol; } } return L; } void Add(int pos,int val,int d) { for(int i=pos;i<=n;i+=i & -i) { seg[i].Add(val,d); } }private: SegTree *seg;int n; int FindNode(int pos,SegTree::Iter nodes[]) { int cnt=0; for(int i=pos;i;i-=i & -i) { nodes[++cnt]=seg[i].root; } return cnt; }}bit;void Init() { DFS(1); ST(); new(&bit) Bit(dc);}void Modify(int x,int y) { bit.Add(lbd[place[x]],force[x],-1); bit.Add(rbd[place[x]]+1,force[x],1); bit.Add(lbd[place[x]],force[x]=y,1); bit.Add(rbd[place[x]]+1,force[x],-1);}void Move(int x,int to) { bit.Add(lbd[place[x]],force[x],-1); bit.Add(rbd[place[x]]+1,force[x],1); bit.Add(lbd[place[x]=to],force[x],1); bit.Add(rbd[place[x]]+1,force[x],-1);}int Query(int p1,int p2,int K,int Ans[]) { int cnt=0; for(int i=1;i<=K;++i) { if((Ans[++cnt]=bit.Kiss(p1,p2,i))==-1) { cnt--; break; } } return cnt;}int main() {// freopen("input","r",stdin);; int n;is>>n; for(int i=1;i<=n-1;++i) { int x,y;is>>x>>y; Adde(x,y); } int m;is>>m; Init(); for(int i=1;i<=m;++i) { is>>force[i]>>place[i]; bit.Add(lbd[place[i]],force[i],1); bit.Add(rbd[place[i]]+1,force[i],-1); } int Q,K;is>>Q>>K; static int Ans[30],ac; for(int i=1;i<=Q;++i) { int opt,x,y;is>>opt>>x>>y; switch(opt) { case 1: if(!(ac=Query(x,y,K,Ans))) { os<<-1<<'\n'; } else { for(int i=1;i<=ac;++i) { os<<Ans[i]<<' ';//<<(i==ac?'\n':' '); } os<<'\n'; } break; case 2: Move(x,y); break; case 3: Modify(x,y); break; } } return 0;}