如果不断边,直接路径+,看边的权值。
这个相当于是区间加,单点查询
如果断边,很多路径变化了,就凉了。
考虑单点加,查询子树内部有没有包含所有的路径的一端。
考虑hash
给两端xor同一个随机值。
这样,子树没有出现或者出现两次都不合法,贡献都是0
出错概率就是每个点都是随机情况下,存在一个子集xor为0
概率很小
单点加,区间查询
其实链处理也是可以的
画画情况发现每个经过(u,v)的都恰好还是对的
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') #define pb push_back #define solid const auto & #define enter cout<<endl #define pii pair<int,int> #define ui unsigned int using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);} template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar(' ');} namespace Modulo{ const int mod=998244353; il int ad(int x,int y){return x+y>=mod?x+y-mod:x+y;} il int sub(int x,int y){return ad(x,mod-y);} il int mul(int x,int y){return (ll)x*y%mod;} il void inc(int &x,int y){x=ad(x,y);} il void inc2(int &x,int y){x=mul(x,y);} il int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;} template<class ...Args>il int ad(const int a,const int b,const Args &...args) {return ad(ad(a,b),args...);} template<class ...Args>il int mul(const int a,const int b,const Args &...args) {return mul(mul(a,b),args...);} } // using namespace Modulo; namespace Miracle{ const int N=1e5+5; int n,m; struct node{ int ch[2],fa; int rev; ui val,sum; ui si; }t[N]; bool nrt(int x){ return ((t[t[x].fa].ch[0]==x)||(t[t[x].fa].ch[1]==x)); } void pushup(int x){ t[x].sum=t[t[x].ch[0]].sum^t[t[x].ch[1]].sum^t[x].val^t[x].si; } #define ls t[x].ch[0] #define rs t[x].ch[1] void rev(int x){ swap(ls,rs); t[x].rev^=1; } void pushdown(int x){ if(t[x].rev){ rev(ls);rev(rs); t[x].rev=0; } } void rotate(int x){ int y=t[x].fa,d=t[y].ch[1]==x; t[t[y].ch[d]=t[x].ch[!d]].fa=y; if(nrt(y)) t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[1]==y]=x; else t[x].fa=t[y].fa; t[t[x].ch[!d]=y].fa=x; pushup(y); } int sta[N]; void splay(int x){ int y=x,z=0; sta[++z]=y; while(nrt(y)) y=t[y].fa,sta[++z]=y; while(z) pushdown(sta[z--]); while(nrt(x)){ y=t[x].fa,z=t[y].fa; if(nrt(y)){ rotate((t[y].ch[0]==x)==(t[z].ch[0]==y)?y:x); } rotate(x); } pushup(x); } void access(int x){ for(reg y=0;x;y=x,x=t[x].fa){ splay(x); t[x].si^=t[y].sum; t[x].si^=t[t[x].ch[1]].sum; t[x].ch[1]=y; pushup(x); } } void makert(int x){ access(x);splay(x);rev(x); } void split(int x,int y){ makert(x);access(y);splay(y); } void link(int x,int y){ split(x,y); t[x].fa=y; t[y].si^=t[x].sum; pushup(y); } void cut(int x,int y){ split(x,y); t[x].fa=t[y].ch[0]=0;pushup(y); } void tag(int x,int c){ access(x);splay(x); t[x].val^=c;pushup(x); } struct path{ int x,y; ui val; }p[3*N]; int cnt; ui tot; vector<int>to[N]; void dfs(int x,int fa){ for(solid y:to[x]){ // int y=e[i].to; if(y==fa) continue; t[y].fa=x; dfs(y,x); } } ui Rand(){ ui le=(rand()<<1)|(rand()&1); ui ri=(rand()<<1)|(rand()&1); return (le<<16)|ri; } int main(){ srand((unsigned long long)new char); int haha;rd(haha); rd(n);rd(m); int x,y; for(reg i=1;i<n;++i){ rd(x);rd(y); to[x].pb(y);to[y].pb(x); } dfs(1,0); int op,u,v; while(m--){ rd(op); if(op==1){ rd(x);rd(y);rd(u);rd(v); cut(x,y);link(u,v); }else if(op==2){ rd(x);rd(y); ++cnt; p[cnt].x=x;p[cnt].y=y; p[cnt].val=Rand(); tot^=p[cnt].val; tag(x,p[cnt].val); tag(y,p[cnt].val); }else if(op==3){ int id; rd(id); x=p[id].x,y=p[id].y; ui val=p[id].val; tot^=val; tag(x,val); tag(y,val); }else{ rd(x);rd(y); split(x,y); if(t[x].sum==tot){ puts("YES"); }else puts("NO"); } } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* */
注意,link的时候,
必须access(y),splay(y),因为要更新y的si值。作为根pushup才行