1. 程式人生 > >2759: 一個動態樹好題

2759: 一個動態樹好題

algorithm The 方程 一個 using mic close IT 是個

發現當存在一個環,就可以求出環所在聯通塊上所有點的答案.

既然題目都告訴我是lct了,就想著搞一搞,

用splay維護每個點對根的方程,即splay維護這顆splay中深度最深的節點對於深度最淺節點的方程

然後腦子木的以為有很多非樹邊,在哪裏各種亂搞,,各種暴力枚舉想水一水...

我大概是個智障.

正解:

邊是有向的,i->p[i]

有腦子的人都會知道這是一顆基環內向樹

基環樹有個套路就是不需要換根操作,把環上一條邊拆了,其中一個點看做根,另一個點看做根的special_father

那麽就很好做了,splay像上面那樣維護.

link的時候如果沒聯通就直接link,否則只是把i的special_father設為p[i]

cut的時候如果是cut掉special_father.直接把special_father設為0

否則先cut成兩個聯通塊,然後找到開始的根,若根的special_father重新聯通這兩個聯通塊就把這條邊變成正常的樹邊,link起來,special_father設為0

查詢的時候,access根的special_father即可算出根的答案,再access要查詢的點即可

技術分享圖片
  1 //Achen
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdlib>
  6
#include<cstdio> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 #include<map> 11 #define For(i,a,b) for(int i=(a);i<=(b);i++) 12 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 13 const int N=30000+7,P=10007; 14 typedef long long LL; 15 typedef double db;
16 using namespace std; 17 int n,Q,inv[P+7]; 18 char o[10]; 19 20 template<typename T>void read(T &x) { 21 char ch=getchar(); x=0; T f=1; 22 while(ch!=-&&(ch<0||ch>9)) ch=getchar(); 23 if(ch==-) f=-1,ch=getchar(); 24 for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f; 25 } 26 27 int ch[N][2],p[N],sp[N],pp[N]; 28 #define lc ch[x][0] 29 #define rc ch[x][1] 30 struct data { 31 int k,b; 32 data(){ k=1; b=0; } 33 data(int k,int b):k(k),b(b){} 34 friend data operator *(const data&A,const data&B) { 35 return data(A.k*B.k%P,(A.b*B.k%P+B.b)%P); 36 } 37 }sum[N],dt[N]; 38 39 int isroot(int x) { return (ch[p[x]][0]!=x&&ch[p[x]][1]!=x); } 40 41 void update(int x) { sum[x]=sum[lc]*dt[x]*sum[rc]; } 42 43 void rotate(int x) { 44 int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1; 45 if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z; 46 ch[y][l]=ch[x][r]; p[ch[x][r]]=y; 47 ch[x][r]=y; p[y]=x; 48 update(y); update(x); 49 } 50 51 void splay(int x) { 52 for(;!isroot(x);rotate(x)) { 53 int y=p[x],z=p[y]; 54 if(!isroot(y)) 55 ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y); 56 } 57 } 58 59 void access(int x) { 60 for(int t=0;x;x=p[t=x]) { 61 splay(x); 62 rc=t; 63 update(x); 64 } 65 } 66 67 int find_root(int x) { 68 access(x); 69 splay(x); 70 while(lc) x=lc; 71 return x; 72 } 73 74 void lik(int x,int y) { 75 if(find_root(x)==find_root(y)) { 76 sp[x]=y; return; 77 } 78 splay(x); 79 p[x]=y; 80 } 81 82 void cut(int x,int y) { 83 if(sp[x]==y) { 84 sp[x]=0; return; 85 } 86 int z=find_root(x); 87 lc=p[lc]=0; 88 update(x); 89 if(sp[z]&&find_root(sp[z])!=find_root(z)) { 90 access(z); 91 splay(z); 92 p[z]=sp[z]; 93 sp[z]=0; 94 } 95 } 96 97 void exgcd(int a,int b,int &x,int &y) { 98 if(!b) { x=1; y=0; return; } 99 exgcd(b,a%b,y,x); y-=a/b*x; 100 } 101 102 void qry(int x) { 103 int y=find_root(x); 104 if(!sp[y]) puts("-2"); 105 else { 106 access(sp[y]); 107 splay(sp[y]); 108 data tp=sum[sp[y]]; 109 if(tp.k&&(!tp.b)) { puts("-1"); return; } 110 int a=(1-tp.k+P)%P; 111 int rs=!tp.k?tp.b:inv[a]*tp.b%P; 112 access(x); 113 splay(x); 114 rs=(sum[x].k*rs%P+sum[x].b)%P; 115 printf("%d\n",rs); 116 } 117 } 118 119 //#define DEBUG 120 int main() { 121 #ifdef DEBUG 122 freopen("1.in","r",stdin); 123 //freopen("1.out","w",stdout); 124 #endif 125 read(n); 126 inv[0]=inv[1]=1; 127 For(i,2,P) inv[i]=(P-P/i*inv[P%i]%P)%P; 128 For(i,1,n) { 129 read(dt[i].k); read(pp[i]); read(dt[i].b); 130 lik(i,pp[i]); 131 } 132 read(Q); 133 while(Q--) { 134 scanf("%s",o); 135 if(o[0]==A) { 136 int xx; 137 read(xx); 138 qry(xx); 139 } 140 else { 141 int xx,kk,ppp,bb; 142 read(xx); read(kk); read(ppp); read(bb); 143 cut(xx,pp[xx]); 144 splay(xx); 145 dt[xx].k=kk; dt[xx].b=bb; 146 update(xx); 147 pp[xx]=ppp; 148 lik(xx,pp[xx]); 149 } 150 } 151 return 0; 152 }
View Code

我真的好菜呀,,什麽"經典模型","套路","眾所周知的" 都不知道,什麽"大水題","送分題","普及-的題"都做不來...

2759: 一個動態樹好題