UOJ189题解
火车司机滚出秦川/fn/fn/fn
考虑把路径上的关键点拉出来建虚圆方树,这样做是 的。
对于虚仙人掌上的每一个点搞两个标记,一个记录子树内有几个走城市多的,一个记录子树内有几个走城市少的。树上差分一下就行了。
对原树上的方圆边记录两个权值:到环的根走城市少的福音的和城市多的福音。
对虚树上的每条圆圆边记录三个权值:只走城市多的福音,只走城市少的福音,原树上在路径上的圆圆边的福音。
通过上面的记录可以轻松算出非环上的贡献,接下来考虑环上的。
如果一个方点有一个儿子,这个儿子的两个标记都不为 ,那么就计算这整个环的代价。对于方点是一条路径的 LCA 需要特判。
否则的话根据标记在这个环上面区间覆盖啥的,这个肯定一只log。
然后修改的话,对每个环开一颗树状数组,然后在上面二分一下。对于上面提到的维护的福音维护一个到根节点的这种类型的福音之和,然后每次修改相当于子树加。
复杂度 。
#include<algorithm>
#include<cstdio>
#include<cctype>
#include<vector>
const int M=3e5+5;
int n,m,q;int dfc,tot,V[M],fa[M],low[M],dfn[M];
int cnt,h[M<<1],f[M<<1],d[M<<1],l[M<<1],r[M<<1],id[M<<1],siz[M<<1],son[M<<1],top[M<<1],DFN[M<<1];
int S1[M<<1],S2[M<<1],S3[M<<1],sum[M<<1];int _BIT[M<<1],_val[M<<1],*BIT[M<<1],*val[M<<1],*nBIT=_BIT,*nval=_val;
char _input[1<<25|1],_output[1<<25|1],*_p1=_input,*_p2=_output;int L[M<<1],R[M<<1];
int BIT1[M<<1],BIT2[M<<1],BIT3[M<<1];int x[M<<1],y[M<<1];
int tp,stk[M<<1];
namespace bit{
inline void Add(int*BIT,int x,int V,const int&m){
while(x<=m)BIT[x]+=V,x+=x&-x;
}
inline int Qry(int*BIT,int x){
int ans(0);while(x>=1)ans+=BIT[x],x^=x&-x;return ans;
}
}
struct SEG{
int l,r;
};std::vector<SEG>seg[M<<1];
struct edge{
int v,w;
};std::vector<edge>G[M];
struct Edge{
int v,nx;int w1,w2,w3;
}e[M<<1];
inline int s1(const int&u){
return S1[u]+bit::Qry(BIT1,l[u]);
}
inline int s2(const int&u){
return S2[u]+bit::Qry(BIT2,l[u]);
}
inline int s3(const int&u){
return S3[u]+bit::Qry(BIT3,l[u]);
}
inline void Add(const int&u,const int&v,int w1=-1,int w2=-1,int w3=-1){
if(!~w1)w1=s1(v)-s1(u);if(!~w2)w2=s2(v)-s2(u);if(!~w3)w3=s3(v)-s3(u);
e[++cnt]=(Edge){v,h[u],w1,w2,w3};h[u]=cnt;
}
inline int min(const int&a,const int&b){
return a>b?b:a;
}
inline int minll(const int&a,const int&b){
return a>b?b:a;
}
inline int max(const int&a,const int&b){
return a>b?a:b;
}
inline void Build(const int&u,int v,int Sum){
int tV=Sum,cnt(1);
for(int x=v;x^u;x=fa[x])sum[x]=Sum,id[x]=cnt,++cnt,Sum+=V[x];
sum[++tot]=Sum;id[tot]=cnt;BIT[tot]=nBIT;val[tot]=nval;nBIT+=cnt+1;nval+=cnt+1;sum[u]=0;Add(u,tot,0,0,0);
int lst=tV;
for(int x=v;x^u;x=fa[x]){
Add(tot,x,(id[x]<<1)<cnt?sum[x]:sum[tot]-sum[x],(id[x]<<1)>cnt?sum[x]:sum[tot]-sum[x],0);
}
for(int x=v;x^u;x=fa[x])bit::Add(BIT[tot],id[x],val[tot][id[x]]=lst,cnt),lst=V[x];
bit::Add(BIT[tot],cnt,val[tot][cnt]=lst,cnt);
}
inline void Tarjan(const int&u){
dfn[u]=low[u]=++dfc;
for(edge&E:G[u])if(E.v^fa[u]){
const int&v=E.v;
if(!dfn[v])fa[v]=u,V[v]=E.w,Tarjan(v),low[u]=min(low[u],low[v]);
else low[u]=min(low[u],dfn[v]);
if(dfn[u]<low[v])Add(u,v,0,0,E.w);
}
for(edge&E:G[u])if(fa[E.v]^u&&dfn[u]<dfn[E.v])Build(u,E.v,E.w);
}
inline void DFS1(const int&u){
siz[u]=1;d[u]=d[f[u]]+1;DFN[u]=++dfc;l[u]=dfc;
for(int v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u]){
f[v]=u;if(v<=n)V[v]=e[E].w3;S1[v]=S1[u]+e[E].w1;S2[v]=S2[u]+e[E].w2;S3[v]=S3[u]+e[E].w3;
DFS1(v);siz[u]+=siz[v];siz[v]>siz[son[u]]&&(son[u]=v);
}
r[u]=dfc;
}
inline void DFS2(const int&u,const int&tp){
top[u]=tp;if(!son[u])return;DFS2(son[u],tp);
for(int E=h[u];E;E=e[E].nx)if(e[E].v^f[u]&&e[E].v^son[u])DFS2(e[E].v,e[E].v);
}
inline int LCA(int u,int v){
while(top[u]^top[v])d[top[u]]>d[top[v]]?u=f[top[u]]:v=f[top[v]];return d[u]>d[v]?v:u;
}
inline int Find(int u,const int&v){
while(top[u]^top[v])if(f[top[u]]==v)return top[u];else u=f[top[u]];return son[v];
}
int a,b,p[M<<1],t[2][M<<1];int u[M<<1],v[M<<1],typ[M<<1];int ans;
struct DS{
int n,sum[M];
inline void init(const int&N){
n=N;for(int i=1;i<=n;++i)sum[i]=0;
}
inline void cover(const int&l,const int&r){
++sum[l];--sum[r+1];
}
inline int Qry(const int&u,int*v){
int S(0);
for(int i=1;i<=n;++i)if(sum[i]+=sum[i-1])S+=bit::Qry(BIT[u],id[v[i]])-bit::Qry(BIT[u],id[v[i-1]]);
return S;
}
}se;
inline int Find(int*v,int L,int R,const int&V){
int ans(L),mid;while(L<=R)id[v[mid=L+R>>1]]>=V?ans=mid,R=mid-1:L=mid+1;return ans;
}
inline void Solve(const int&u){
static int m,id[M];int x(0),y(0);m=0;
for(int E=h[u];E;E=e[E].nx)id[++m]=e[E].v;
std::sort(id+1,id+m+1,[&](const int&x,const int&y){return::id[x]<::id[y];});id[++m]=u;
for(int i=1;i<=m-1;++i)if(t[(::id[id[i]]<<1)>::id[u]][id[i]])x=i;
for(int i=m-1;i>=1;--i)if(t[(::id[id[i]]<<1)<::id[u]][id[i]])y=i;
se.init(m);if(x)se.cover(1,x);if(y)se.cover(y+1,m);
for(SEG&S:seg[u])se.cover(Find(id,0,m,S.l)+1,Find(id,0,m,S.r));ans+=se.Qry(u,id);
}
inline void DFS(const int&u){
for(int v,E=h[u];E;E=e[E].nx){
DFS(v=e[E].v);
if(u<=n){
if(t[0][v])ans+=e[E].w1;if(t[1][v])ans+=e[E].w2;if(t[0][v]||t[1][v])ans+=e[E].w3;
}
t[0][u]+=t[0][v];t[1][u]+=t[1][v];
}
if(u>n)Solve(u),std::vector<SEG>().swap(seg[u]);
for(int E=h[u];E;E=e[E].nx)if(e[E].v^f[u])t[0][e[E].v]=t[1][e[E].v]=h[e[E].v]=0;
}
inline bool cmp(const int&u,const int&v){
return DFN[u]<DFN[v];
}
inline void Insert(const int&u){
if(!tp)return void(stk[tp=1]=u);
const int&v=LCA(u,stk[tp]);while(tp>1&&d[stk[tp-1]]>d[v])Add(stk[tp-1],stk[tp]),--tp;
if(d[stk[tp]]>d[v])Add(v,stk[tp]),--tp;if(!tp||stk[tp]^v)stk[++tp]=v;if(stk[tp]^u)stk[++tp]=u;
}
inline void insert(const int&u,const int&v){
const int&lca=LCA(u,v);
if(lca>n){
const int&ls=Find(u,lca),&rs=Find(v,lca);
if(ls^u)p[++b]=ls;if(rs^v)p[++b]=rs;
}
}
inline int Build(){
static bool vis[M<<1];
std::sort(p+1,p+a+1,cmp);a=std::unique(p+1,p+a+1)-p-1;b=a;tp=0;
for(int i=1;i<a;++i)insert(p[i],p[i+1]);for(int i=1;i<=a;++i)vis[p[i]]=true;
for(int i=1;i<=a;++i)if(f[p[i]]>n&&!vis[f[p[i]]]&&vis[f[f[p[i]]]])vis[p[++b]=f[p[i]]]=true;a=b;
for(int i=1;i<=a;++i)vis[p[i]]=false;std::sort(p+1,p+a+1,cmp);a=std::unique(p+1,p+a+1)-p-1;
for(int i=1;i<=a;++i)Insert(p[i]);while(tp>1)Add(stk[tp-1],stk[tp]),--tp;
return stk[1];
}
inline int Sol(const int&rt){
return ans=0,DFS(rt),t[0][rt]=t[1][rt]=h[rt]=0,ans;
}
inline void INS(const int&u,const int&v,const int&typ){
const int&lca=LCA(u,v);
if(lca<=n){
++t[typ][u];++t[typ][v];t[typ][lca]-=2;
}
else{
int ls=Find(u,lca),rs=Find(v,lca);
if(u^ls)++t[typ][u],--t[typ][ls];
if(v^rs)++t[typ][v],--t[typ][rs];
if((ls=id[ls])>(rs=id[rs]))ls^=rs^=ls^=rs;
if(typ==((rs-ls<<1)>id[lca]))seg[lca].push_back((SEG){ls,rs});
else seg[lca].push_back((SEG){rs,id[lca]}),seg[lca].push_back((SEG){0,ls});
}
}
inline int read(){
int n(0);char s;while(!isdigit(s=*_p1++));while(n=n*10+(s&15),isdigit(s=*_p1++));return n;
}
inline void write(int n){
static char s[18];int top(0);while(s[++top]=n%10^48,n/=10);while(*_p2++=s[top],--top);*_p2++=10;
}
inline void mdf(){
int qwq,VL;qwq=read();VL=read();
if(qwq){
int u=x[qwq],v=y[qwq];
if(d[v]==d[u]+1){
const int value=VL-V[v];V[v]=VL;
bit::Add(BIT3,l[v],+value,tot);bit::Add(BIT3,r[v]+1,-value,tot);
}
else{
int x=!id[u]?id[v]==1?v:u:v;
const int fa=f[d[f[u]]>d[f[v]]?u:v],value=VL-val[fa][x=id[id[x]?x:fa]];
val[fa][x]=VL;bit::Add(BIT[fa],x,value,id[fa]);
if(min(id[u],id[fa]-id[u])>min(id[v],id[fa]-id[v]))u^=v^=u^=v;
if(id[u]+id[v]==id[fa]){
bit::Add(BIT2,l[fa]+1,+value,tot);bit::Add(BIT2,r[fa]+1,-value,tot);
}
else if(L[fa]<=l[v]){
bit::Add(BIT2,l[fa]+1,+value,tot);bit::Add(BIT2,R[fa]+1,-value,tot);
bit::Add(BIT1,L[fa],+value,tot);bit::Add(BIT1,r[v]+1,-value,tot);
if(u^f[fa])bit::Add(BIT2,l[u],+value,tot),bit::Add(BIT2,r[fa]+1,-value,tot);
}
else{
bit::Add(BIT2,L[fa],+value,tot);bit::Add(BIT2,r[fa]+1,-value,tot);
bit::Add(BIT1,l[v],+value,tot);bit::Add(BIT1,R[fa]+1,-value,tot);
if(u^f[fa])bit::Add(BIT2,l[fa]+1,+value,tot),bit::Add(BIT2,r[u]+1,-value,tot);
}
}
}
}
signed main(){
fread(_input,1,1<<25,stdin);
n=read();m=read();q=read();tot=n;
for(int u,v,w,i=1;i<=m;++i){
u=read();v=read();w=read();G[u].push_back((edge){v,w});G[v].push_back((edge){u,w});x[i]=u;y[i]=v;
}
Tarjan(1);dfc=0;DFS1(1);DFS2(1,1);
for(int u=n+1;u<=n+tot;++u){
static int m,p[M];
m=0;for(int E=h[u];E;E=e[E].nx)if(e[E].v^f[u])p[++m]=l[e[E].v];std::sort(p+1,p+m+1);L[u]=p[m/2+1];
m=0;for(int E=h[u];E;E=e[E].nx)if(e[E].v^f[u])p[++m]=r[e[E].v];std::sort(p+1,p+m+1);R[u]=p[m/2];
}
for(int u=1;u<=tot;++u)h[u]=0;
for(int i=1;i<=m;++i){
if(d[x[i]]==d[y[i]]+1||d[y[i]]==d[x[i]]+1){
if(d[x[i]]>d[y[i]])x[i]^=y[i]^=x[i]^=y[i];
}
else if(id[y[i]]<id[x[i]])x[i]^=y[i]^=x[i]^=y[i];
}
while(q--){
int k,rt;k=read();cnt=0;a=b=0;
if(!k)write(0);
else{
for(int i=1;i<=k;++i)p[++a]=u[i]=read(),p[++a]=v[i]=read(),typ[i]=read();rt=Build();
for(int i=1;i<=k;++i)INS(u[i],v[i],typ[i]);write(Sol(rt));
}
mdf();
}
fwrite(_output,1,_p2-_output,stdout);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】