平凡的线段树分治+LCT,一开始只有 60pts。看题解发现写法几乎一样,但这份代码就是卡在 60pts…… 求助到底是哪里慢了?
#define N 100010
#define lc k<<1
#define rc k<<1|1
#define isroot(x) (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x)
#define get(x) (ch[fa[x]][1]==x)
inline void rev(int x){if(x) tag[x]^=1,swap(ch[x][0],ch[x][1]);}
inline int read()
{
register int x=0,c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
inline void pushup(int x)
{
if(!x) return;mxid[x]=x;
mxid[x]=mxid[val[mxid[x]]>val[mxid[ch[x][0]]]?x:ch[x][0]];
mxid[x]=mxid[val[mxid[x]]>val[mxid[ch[x][1]]]?x:ch[x][1]];
return;
}
inline void pushdown(int k)
{
if(!tag[k]) return;
rev(ch[k][0]),rev(ch[k][1]);
return void(tag[k]=0);
}
inline void update(int x)
{
while(!isroot(x)) node[++node[0]]=x,x=fa[x];
node[++node[0]]=x;
while(node[0]) pushdown(node[node[0]--]);
return;
}
inline void zug(int x)
{
int y=fa[x],z=fa[y],k=get(x);
if(!isroot(y)) ch[z][get(y)]=x;
ch[y][k]=ch[x][!k],fa[ch[x][!k]]=y;
ch[x][!k]=y,fa[y]=x,fa[x]=z;
return pushup(y),pushup(x);
}
inline void splay(int x)
{
update(x);
for(int f=fa[x];!isroot(x);zug(x),f=fa[x])
if(!isroot(f)) zug(get(x)==get(f)?f:x);
return;
}
inline void access(int x)
{
for(int p=0;x;p=x,x=fa[x])
splay(x),ch[x][1]=p,pushup(x);
return;
}
inline void makeroot(int x)
{
access(x),splay(x);
return rev(x);
}
inline int findroot(int x)
{
access(x),splay(x);
while(ch[x][0]) x=ch[x][0],pushdown(x);
splay(x);return x;
}
inline void link(int x,int y)
{
makeroot(x);
access(y),splay(y),fa[x]=y;
return;
}
inline void cut(int x,int y)
{
makeroot(x);
access(y),splay(y);
ch[y][0]=fa[x]=0;
return pushup(y);
}
inline int query(int x,int y)
{
makeroot(x);
access(y),splay(y);
return mxid[y];
}
inline void modify(int k,int l,int r,int x,int y,int nw)
{
if(l >= x && r <= y) {h[k].push_back(nw);return;}
int mid=l+r>>1;
if(x <= mid) modify(lc,l,mid,x,y,nw);
if(mid < y) modify(rc,mid+1,r,x,y,nw);
return;
}
inline void maintain(int x)
{
int nw;
if(findroot(fr[x]) != findroot(to[x]))
link(fr[x],x),link(to[x],x),sta[++top]=pair<int,bool>(x,0),ans+=val[x];
else if(val[nw=query(fr[x],to[x])] > val[x])
{
cut(fr[nw],nw),cut(to[nw],nw),sta[++top]=pair<int,bool>(nw,1),ans-=val[nw];//first存虚点,second存删还是加。fr,to为边的端点
link(fr[x],x),link(to[x],x),sta[++top]=pair<int,bool>(x,0),ans+=val[x];
}
return;
}
inline void undone(int lim)
{
for(pair<int,bool> x=sta[top];top>lim;x=sta[--top])
if(x.second) link(fr[x.first],x.first),link(to[x.first],x.first),ans+=val[x.first];
else cut(fr[x.first],x.first),cut(to[x.first],x.first),ans-=val[x.first];
return;
}
inline void solve(int k,int l,int r)
{
int cpy=top,mid=l+r>>1;
for(unsigned int i=0;i<h[k].size();i++) maintain(h[k][i]);
if(l == r) printf("%lld\n",ans);
else solve(lc,l,mid),solve(rc,mid+1,r);
return undone(cpy);
}
int main()
{
n=read(),m=read(),q=read(),tot=n;
For(i,1,m)
{
f[i]=read(),t[i]=read(),d[i]=read();
lst[i]=1,lstid[i]=++tot,val[tot]=d[i];
fr[tot]=f[i],to[tot]=t[i];//建立虚点,边权转点权
}
For(i,1,q)
{
int id=read(),nd=read();
if(lst[id] < i) modify(1,1,q,lst[id],i-1,lstid[id]);
lst[id]=i,lstid[id]=++tot,val[tot]=nd;
fr[tot]=f[id],to[tot]=t[id];
}For(i,1,m) modify(1,1,q,lst[i],q,lstid[i]);
solve(1,1,q);
return 0;
}