BZOJ 3091 城市旅行

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

Sample Output

16/3
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\n"); 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\n",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 }
View Code

 

转载于:https://www.cnblogs.com/mmlz/p/4274850.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值