1. 程式人生 > >【HNOI2010】bzoj2002 彈飛綿羊【解法二】

【HNOI2010】bzoj2002 彈飛綿羊【解法二】

Description

某天,Lostmonkey發明了一種超級彈力裝置,為了在他的綿羊朋友面前顯擺,他邀請小綿羊一起玩個遊戲。遊戲一開始,Lostmonkey在地上沿著一條直線擺上n個裝置,每個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會往後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。綿羊想知道當它從第i個裝置起步時,被彈幾次後會被彈飛。為了使得遊戲更有趣,Lostmonkey可以修改某個彈力裝置的彈力系數,任何時候彈力系數均為正整數。
Input

第一行包含一個整數n,表示地上有n個裝置,裝置的編號從0到n-1,接下來一行有n個正整數,依次為那n個裝置的初始彈力系數。第三行有一個正整數m,接下來m行每行至少有兩個數i、j,若i=1,你要輸出從j出發被彈幾次後被彈飛,若i=2則還會再輸入一個正整數k,表示第j個彈力裝置的係數被修改成k。對於20%的資料n,m<=10000,對於100%的資料n<=200000,m<=100000
Output

對於每個i=1的情況,你都要輸出一個需要的步數,佔一行。

解法一LCT見【這裡】
分成n塊,對於每個點記錄跳幾次才能出了自己的塊以及跳到哪裡,對於詢問就從這個點開始跳一遍,對於修改就暴力重算所屬塊的所有元素,複雜度O(mn)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int oo=0x3f3f3f3f;
int rd()
{
    int x=0;
    char c=getchar();
    while
(c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x; } struct edge { int u,v,a,b; void read() { u=rd(); v=rd(); a=rd(); b=rd(); } bool operator < (const edge &e) const
{ return a<e.a; } }g[100010]; int fa[400010],son[400010][2],sta[400010],w[400010],mx[400010],tag[400010], n,m,ans=oo; int isroot(int u) { return son[fa[u]][0]!=u&&son[fa[u]][1]!=u; } void up(int u) { mx[u]=u; if (son[u][0]&&w[mx[son[u][0]]]>w[mx[u]]) mx[u]=mx[son[u][0]]; if (son[u][1]&&w[mx[son[u][1]]]>w[mx[u]]) mx[u]=mx[son[u][1]]; } void down(int u) { if (tag[u]) { if (son[u][0]) tag[son[u][0]]^=1; if (son[u][1]) tag[son[u][1]]^=1; swap(son[u][0],son[u][1]); tag[u]=0; } } void rot(int u,int k) { int v=son[u][k],w=son[v][k^1],p=fa[u]; if (!isroot(u)) son[p][son[p][1]==u]=v; fa[v]=p; son[u][k]=w; fa[w]=u; son[v][k^1]=u; fa[u]=v; up(u); up(v); up(p); } void splay(int u) { int top=0,x,y,v,w; for (int i=u;;i=fa[i]) { sta[++top]=i; if (isroot(i)) break; } for (;top;top--) down(sta[top]); while (!isroot(u)) { v=fa[u]; x=son[v][1]==u; if (isroot(v)) rot(v,x); else { w=fa[v]; y=son[w][1]==v; if (x==y) { rot(w,x); rot(v,x); } else { rot(v,x); rot(w,y); } } } } void access(int u) { int v=0; while (u) { splay(u); son[u][1]=v; up(u); v=u; u=fa[u]; } } void makeroot(int u) { access(u); splay(u); tag[u]^=1; } int find(int u) { access(u); splay(u); while (son[u][0]) u=son[u][0]; return u; } void link(int u,int v) { makeroot(u); fa[u]=v; } void cut(int u,int v) { makeroot(u); access(v); splay(v); son[v][0]=fa[u]=0; up(v); } int qry(int u,int v) { makeroot(u); access(v); splay(v); return mx[v]; } int main() { int u; n=rd(); m=rd(); for (int i=1;i<=m;i++) g[i].read(); sort(g+1,g+m+1); for (int i=1;i<=n;i++) mx[i]=i; for (int i=1;i<=m;i++) { w[n+i]=g[i].b; mx[n+i]=n+i; if (find(g[i].u)!=find(g[i].v)) { link(n+i,g[i].u); link(n+i,g[i].v); } else { u=qry(g[i].u,g[i].v); if (w[u]>w[n+i]) { cut(u,g[u-n].u); cut(u,g[u-n].v); link(i+n,g[i].u); link(i+n,g[i].v); } } if (find(1)==find(n)) ans=min(ans,g[i].a+w[qry(1,n)]); } if (ans==oo) printf("-1\n"); else printf("%d\n",ans); }