Description
Input
Output
Sample Input
4 5
1 3 2 5
1 2
1 3
2 4
4 2 4
1 2 4
2 3 4
3 1 4 1
4 1 4
1 3 2 5
1 2
1 3
2 4
4 2 4
1 2 4
2 3 4
3 1 4 1
4 1 4
Sample Output
16/3
6/1
6/1
HINT
对于所有数据满足 1<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N
Source
维护方法我就不再赘述了,见我博客的 BZOJ 2572 高速公路。这一题和那一题的维护方法其实是一样的,但是数据结构不同,很明显这是lct嘛。
但是那么问题就来,树上的序号id不是一定的,不像线段树一样,怎么办呢???
这就是本题的难点——维护id。但是细细想想其实也不是很难。
你想,他是要维护一条链上深度的id,左子树id<右子树,其实我们就是在access操作中对某一条链的id整体加上一个值或者减去一个值,这样来操作(splay维护的都是一条链)。因此,维护id就不成问题。
但是你有没有考虑过这样一种情况:根翻转了,他所在splay的id也全部都要翻转,这怎么办?其实也不难,将其所在splay中所有id都取负,再加上splay的size+1即可。
代码实现有许多的细节要处理:比如初始化连边,他貌似卡了你的link,如果你直接连的话,正确的做法是dfs直接将father连上去(这就是我开始tle了八九发的原因)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 using namespace std; 5 6 typedef long long ll; 7 #define maxn 50010 8 int n,m,ch[maxn][2],size[maxn],fa[maxn],stack[maxn]; 9 int side[maxn],next[maxn*2],toit[maxn*2],cnt; 10 ll key[maxn],id[maxn],s1[maxn],s2[maxn],s3[maxn]; 11 ll lef[maxn],rig[maxn],sign1[maxn],sign2[maxn]; 12 bool rev[maxn]; 13 14 inline int getint() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 18 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 22 inline ll getlong() 23 { 24 ll x=0,f=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 30 inline ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } 31 32 inline void pushdown(int x) 33 { 34 int lc = ch[x][0],rc = ch[x][1]; 35 if (rev[x]) 36 { 37 id[x] = -id[x]; s2[x] = -s2[x]; 38 swap(lef[x],rig[x]); 39 lef[x] = -lef[x]; rig[x] = -rig[x]; 40 swap(ch[x][0],ch[x][1]); 41 if (lc) rev[lc] ^= 1,sign2[lc] = -sign2[lc]; 42 if (rc) rev[rc] ^= 1,sign2[rc] = -sign2[rc]; 43 rev[x] = false; 44 } 45 if (sign2[x]) 46 { 47 lef[x] += sign2[x]; rig[x] += sign2[x]; id[x] += sign2[x]; 48 s3[x] += (sign2[x]*s2[x]<<1)+sign2[x]*sign2[x]*s1[x]; 49 s2[x] += sign2[x]*s1[x]; 50 if (lc) sign2[lc] += sign2[x]; 51 if (rc) sign2[rc] += sign2[x]; 52 sign2[x] = 0; 53 } 54 if (sign1[x]) 55 { 56 s1[x] += sign1[x]*(ll)size[x]; 57 s2[x] += (ll)size[x]*(lef[x]+rig[x])/2*sign1[x]; 58 s3[x] += (rig[x]*(rig[x]+1)*((rig[x]<<1)+1)/6-(lef[x]-1)*lef[x]*((lef[x]<<1)-1)/6)*sign1[x]; 59 key[x] += sign1[x]; 60 if (lc) sign1[lc] += sign1[x]; 61 if (rc) sign1[rc] += sign1[x]; 62 sign1[x] = 0; 63 } 64 } 65 66 inline void updata(int x) 67 { 68 int lc = ch[x][0],rc = ch[x][1]; 69 if (lc) pushdown(lc); if (rc) pushdown(rc); 70 size[x] = size[lc]+size[rc]+1; 71 s1[x] = s1[lc]+s1[rc]+key[x]; 72 s2[x] = id[x]*key[x]+s2[lc]+s2[rc]; 73 s3[x] = id[x]*id[x]*key[x]+s3[lc]+s3[rc]; 74 lef[x] = rig[x] = id[x]; 75 if (lc) lef[x] = lef[lc]; 76 if (rc) rig[x] = rig[rc]; 77 } 78 79 inline bool isroot(int a) { return ch[fa[a]][0] != a&&ch[fa[a]][1] != a; } 80 81 inline void rotate(int x) 82 { 83 int y = fa[x],z = fa[y],l = ch[y][1]==x,r = l^1; 84 if (!isroot(y)) ch[z][ch[z][1]==y] = x; fa[x] = z; 85 if (ch[x][r]) fa[ch[x][r]] = y; ch[y][l] = ch[x][r]; 86 ch[x][r] = y; fa[y] = x; 87 updata(y); updata(x); 88 } 89 90 inline void splay(int x) 91 { 92 int top = 0,i; 93 for (i = x;!isroot(i);i = fa[i]) stack[++top] = i; 94 stack[++top] = i; 95 while (top) pushdown(stack[top--]); 96 while (!isroot(x)) 97 { 98 int y = fa[x],z = fa[y]; 99 if (!isroot(y)) 100 { 101 if ((ch[y][0]==x)^(ch[z][0]==y)) rotate(x); 102 else rotate(y); 103 } 104 rotate(x); 105 } 106 } 107 108 inline int access(int x) 109 { 110 int t; 111 for (t = 0;x;t = x,x = fa[x]) 112 { 113 splay(x); 114 if (ch[x][1]) sign2[ch[x][1]] -= size[ch[x][0]]+1; 115 ch[x][1] = t; 116 if (t) sign2[t] += size[ch[x][0]]+1; 117 updata(x); 118 } 119 return t; 120 } 121 122 inline void evert(int x) 123 { 124 x = access(x); rev[x] ^= 1; 125 sign2[x] += rev[x]*(size[x]+1); 126 } 127 128 inline int find(int x) 129 { 130 x = access(x); 131 while (pushdown(x),ch[x][0]) x = ch[x][0]; 132 return x; 133 } 134 135 inline void cut(int x,int y) 136 { 137 evert(x); access(y); splay(y); 138 if (ch[y][0] != x||ch[x][1] != 0) return; 139 ch[y][0] = fa[x] = 0; 140 updata(x); 141 sign2[y] -= size[x]; 142 } 143 144 inline void link(int x,int y) 145 { 146 if (find(x) == find(y)) return; 147 evert(x); fa[x] = y; 148 } 149 150 inline void change(int x,int y,ll v) 151 { 152 if (find(x) != find(y)) return; 153 evert(x); x = access(y); 154 sign1[x] += v; 155 pushdown(x); 156 } 157 158 inline void ask(int x,int y) 159 { 160 if (find(x) != find(y)) { printf("-1 "); return; } 161 evert(x); access(y); splay(x); 162 ll up = -s3[x]+(ll)(size[x]+1)*s2[x],down = (ll)size[x]*(ll)(size[x]+1)>>1,d = gcd(up,down); 163 up /= d; down /= d; 164 printf("%lld/%lld ",up,down); 165 } 166 167 inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; } 168 169 inline void ins(int a,int b) { add(a,b); add(b,a); } 170 171 inline void dfs(int now,int f) 172 { 173 if (f) fa[now] = f; 174 for (int i = side[now];i;i = next[i]) 175 if (toit[i] != f) dfs(toit[i],now); 176 } 177 178 int main() 179 { 180 freopen("3091.in","r",stdin); 181 freopen("3091.out","w",stdout); 182 scanf("%d %d",&n,&m); 183 for (int i = 1;i <= n;++i) 184 { 185 key[i] = getlong(); 186 s1[i] = s2[i] = s3[i] = key[i]; 187 size[i] = lef[i] = rig[i] = id[i] = 1; 188 } 189 for (int i = 1;i < n;++i) 190 { 191 int a = getint(),b = getint(); 192 ins(a,b); 193 } 194 dfs(1,0); 195 while (m--) 196 { 197 int opt = getint(); 198 if (opt == 3) 199 { 200 int u = getint(),v = getint(); ll d = getlong(); 201 change(u,v,d); 202 } 203 else 204 { 205 int u = getint(),v = getint(); 206 if (opt == 1) cut(u,v); 207 else if (opt == 2) link(u,v); 208 else ask(u,v); 209 } 210 } 211 fclose(stdin); fclose(stdout); 212 return 0; 213 }