[BZOJ]2959: 长跑
题解: 我们考虑一条链时 答案为链上和 路径上有环时 这个环上的点都会产生贡献 然后我们可以 用并查集来维护LCT 有环时直接缩成一个点即可
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=3e5+10; const double eps=1e-8; #define ll long long using namespace std; struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } int res[MAXN],pre[MAXN],ch[MAXN][2],key[MAXN],sum[MAXN]; int f[MAXN]; bool rt[MAXN]; int find1(int x){ if(x==f[x])return x; return f[x]=find1(f[x]); } int a[MAXN]; void newnode(int t){ res[t]=pre[t]=ch[t][0]=ch[t][1]=0;key[t]=sum[t]=a[t];rt[t]=1; } void reverse(int x){ if(!x)return ; swap(ch[x][0],ch[x][1]); res[x]^=1; } void push(int x){ if(res[x]){ reverse(ch[x][0]); reverse(ch[x][1]); res[x]^=1; } } void up(int x){sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+key[x];} void P(int x){ if(!rt[x])P(find1(pre[x])); push(x); } void rotate(int x,int kind){ int y=find1(pre[x]); ch[y][!kind]=ch[x][kind];pre[ch[x][kind]]=y; if(rt[y])rt[y]=0,rt[x]=1; else ch[find1(pre[y])][ch[find1(pre[y])][1]==y]=x; pre[x]=find1(pre[y]);ch[x][kind]=y;pre[y]=x; up(y); } void splay(int x){ P(x); while(!rt[x]){ if(rt[find1(pre[x])])rotate(x,ch[find1(pre[x])][0]==x); else{ int y=find1(pre[x]);int kind=ch[find1(pre[y])][0]==y; if(ch[y][kind]==x)rotate(x,!kind),rotate(x,kind); else rotate(y,kind),rotate(x,kind); } } up(x); } void access(int x){ int y=0; while(x){ splay(x); if(ch[x][1])rt[ch[x][1]]=1,pre[ch[x][1]]=x,ch[x][1]=0; if(rt[y])rt[y]=0; ch[x][1]=y;up(x); y=x;x=find1(pre[x]); } } bool pd(int u,int v){ u=find1(u);v=find1(v); while(pre[u])u=find1(pre[u]); while(pre[v])v=find1(pre[v]); return u==v; } void mroot(int u){access(u);splay(u);reverse(u);} int st[MAXN],tot; void dfs(int x){ if(!x)return ; st[++tot]=x; push(x); dfs(ch[x][0]); dfs(ch[x][1]); } void Tarjan(int u,int v){ u=find1(u);v=find1(v); mroot(u);access(v);splay(v); tot=0;dfs(v); int ans=key[st[1]]; //if(tot==1)cout<<"sb"<<endl; inc(i,2,tot){ ans+=key[st[i]]; int t1=find1(st[i-1]); int t2=find1(st[i]); if(t1==t2)continue; if(t1>t2)swap(t1,t2); f[t2]=t1; } inc(i,1,tot)rt[st[i]]=1,ch[st[i]][0]=ch[st[i]][1]=0,pre[st[i]]=0; key[find1(st[1])]=sum[find1(st[1])]=ans; splay(find1(st[1])); up(find1(st[1])); } void update(int x,int k){ int t=find1(x); access(t);splay(t);key[t]+=(k-a[x]); a[x]=k;up(t); } void Link(int u,int v){ u=find1(u);v=find1(v); mroot(u);mroot(v); pre[u]=v; } int query(int u,int v){ if(!pd(u,v))return -1; int t1=find1(u);int t2=find1(v); if(t1==t2)return key[t1]; mroot(t1);access(t2);splay(t2); return sum[t2]; } int main(){ int n=read();int m=read(); inc(i,1,n)a[i]=read(),newnode(i),f[i]=i; int op,x,y; while(m--){ op=read();x=read();y=read(); if(op==1){ if(find1(x)==find1(y))continue; if(pd(x,y))Tarjan(x,y); else Link(x,y); } else if(op==2)update(x,y); else printf("%d\n",query(x,y)); } return 0; }
2959: 长跑
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1244 Solved: 614
[Submit][Status][Discuss]
Description
某校开展了同学们喜闻乐见的阳光长跑活动。为了能“为祖国健康工作五十年”,同学们纷纷离开寝室,离开教室,离开实验室,到操场参加3000米长跑运动。一时间操场上熙熙攘攘,摩肩接踵,盛况空前。
为了让同学们更好地监督自己,学校推行了刷卡机制。
学校中有n个地点,用1到n的整数表示,每个地点设有若干个刷卡机。
有以下三类事件:
1、修建了一条连接A地点和B地点的跑道。
2、A点的刷卡机台数变为了B。
3、进行了一次长跑。问一个同学从A出发,最后到达B最多可以刷卡多少次。具体的要求如下:
当同学到达一个地点时,他可以在这里的每一台刷卡机上都刷卡。但每台刷卡机只能刷卡一次,即使多次到达同一地点也不能多次刷卡。
为了安全起见,每条跑道都需要设定一个方向,这条跑道只能按照这个方向单向通行。最多的刷卡次数即为在任意设定跑道方向,按照任意路径从A地点到B地点能刷卡的最多次数。
Input
输入的第一行包含两个正整数n,m,表示地点的个数和操作的个数。
第二行包含n个非负整数,其中第i个数为第个地点最开始刷卡机的台数。
接下来有m行,每行包含三个非负整数P,A,B,P为事件类型,A,B为事件的两个参数。
最初所有地点之间都没有跑道。
每行相邻的两个数之间均用一个空格隔开。表示地点编号的数均在1到n之间,每个地点的刷卡机台数始终不超过10000,P=1,2,3。
Output
输出的行数等于第3类事件的个数,每行表示一个第3类事件。如果该情况下存在一种设定跑道方向的方案和路径的方案,可以到达,则输出最多可以刷卡的次数。如果A不能到达B,则输出-1。
Sample Input
10 20 30 40 50 60 70 80 90
3 1 2
1 1 3
1 1 2
1 8 9
1 2 4
1 2 5
1 4 6
1 4 7
3 1 8
3 8 8
1 8 9
3 8 8
3 7 5
3 7 3
1 4 1
3 7 5
3 7 3
1 5 7
3 6 5
3 3 6
1 2 4
1 5 5
3 3 6
2 8 180
3 8 8
2 9 190
3 9 9
2 5 150
3 3 6
2 1 210
3 3 6
Sample Output
-1
-1
80
170
180
170
190
170
250
280
280
270
370
380
580
HINT
数据规模及约定
对于100%的数据,m<=5n,任意时刻,每个地点的刷卡机台数不超过10000。N<=1.5×105