@ysner
2018-07-17T09:47:41.000000Z
字数 7994
阅读 1854
树上差分
二分
给一棵个点、条边的基环树,钦定要走环就必须要经过某条边,因此两点间路径唯一。边有边权,现有次行动,每次将两点间路径上的边权同时减去一值,问第几次行动后出现负边权。
毒瘤出题人坑害机房多位大佬,出现多人怒码却的惨状。
好像我也只有10分
把图看成根节点连成一个环的几颗树的集合。
暴力模拟即可。
复杂度
然而打不对。。。
可以用一颗线段树维护整个环的边权。
线段树维护环,树剖+线段树维护几颗树。
即数据结构优化后的模拟
复杂度降到
据说码量可以达到???
还有一种方法。
去掉钦定边,图就变成了一棵树。把该边一个点作为树的根,另一点为。
如果两点路径不经过环,直接修改即可。
如果经过,修改一个点到路径,另一点到的路径和那条钦定边。
判断方法是两点与在树上的(分别代表着两点进入环时到的点)不同,如果深度小就连,大就连。
复杂度同,但常数肯定小一些,因不需要线段树。
原理:在序中,两个点的出现在两个点第一次出现的位置之间,且为中间这些数中深度最小的点。
显然。
il void dfs(re int u,re int deep)
{
id[u]=++top;sta[top]=u;d[top]=deep;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(id[v]) continue;
dfs(v,deep+1);
sta[++top]=u;d[top]=deep;
}
}
int main()
{
memset(h,-1,sizeof(h));
n=gi();q=gi();rt=gi();
fp(i,1,n-1)
{
re int u=gi(),v=gi();
add(u,v);add(v,u);
}
dfs(rt,1);
fp(i,1,top) f[0][i]=d[i],dp[0][i]=sta[i];
for(re int i=1;i<=log(top)/log(2);i++)
for(re int j=1;j<=top-(1<<i)+1;j++)
{
if(f[i-1][j]<f[i-1][j+(1<<(i-1))]) f[i][j]=f[i-1][j],dp[i][j]=dp[i-1][j];
else f[i][j]=f[i-1][j+(1<<(i-1))],dp[i][j]=dp[i-1][j+(1<<(i-1))];
}
//printf("good\n");
fp(i,1,q)
{
re int l=gi(),r=gi();
l=id[l],r=id[r];
if(l>r) swap(l,r);
re int k=0;
while((1<<k)<=r-l+1) ++k;
--k;
if(f[k][l]<f[k][r-(1<<k)+1]) printf("%d\n",dp[k][l]);
else printf("%d\n",dp[k][r-(1<<k)+1]);
}
return 0;
}
此题原型借教室。
毒瘤改了一下变成在基环树边上建教室。。。。
于是我们可以发现,我们可以用树上差分来维护树上边权。
给两点之间的路径权值的具体做法,就变成了在两个点上都打上的标记,再在上打的标记。
当然,打上所有标记后我们是不能得到某一步后(过程中)的边权的。
所以我们要用二分答案来逼近出现负边权的确切次数。
然而,求和求次操作后的边权都是复杂度瓶颈,复杂度可达。
注意到二分时每次重求边权未免过于浪费,可以在上一次的基础上继续打标记(往前推就打反标记),再继续推。复杂度可降为。
作为一只懒于打数据结构的蒟蒻,我当然选择方法二啦
树链剖分求,期望得分
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define ls x<<1
#define rs x<<1|1
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e5+100;
unsigned int SA,SB,SC;
int n,m,h[N],cnt,hu,hv,hw,rt,d[N],f[N],sz[N],son[N],top[N],L[N],R[N],id[N],tim,las,c[N],flag=0;
bool vis[N<<1];
struct dat{int u,v,w,tag,lca,gen,lca1;}a[N*100];
struct Edge{int to,nxt,w,id;}e[N<<1];
il void add(re int u,re int v,re ll w,re int id){e[++cnt]=(Edge){v,h[u],w,id};h[u]=cnt;}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
unsigned int rng61()
{
SA^=SA<<16;SA^=SA>>5;SA^=SA<<1;
unsigned int t=SA;
SA=SB;SB=SC;SC^=t^SA;
return SC;
}
il void dfs1(re int u,re int fa)
{
d[u]=d[fa]+1;f[u]=fa;sz[u]=1;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==fa) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
il void dfs2(re int u,re int up)
{
top[u]=up;L[u]=++tim;id[tim]=u;
if(son[u]) dfs2(son[u],up);
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==f[u]||v==son[u]) continue;
dfs2(v,v);
}
R[u]=tim;
}
il int getlca(re int u,re int v)
{
while(top[u]^top[v])
{
if(d[top[u]]<d[top[v]]) swap(u,v);
u=f[top[u]];
}
return d[u]<d[v]?u:v;
}
il void dfs(re int u,re int fa)
{
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
c[u]+=c[v];
e[i].w+=c[v];
c[v]=0;
if(e[i].w<0) flag=1,vis[e[i].id]=1;else vis[e[i].id]=0;
}
}
il int check(re int x)
{
flag=0;
if(las<x)
{
fp(i,las+1,x)
{
re int u=a[i].u,v=a[i].v,w=a[i].w,lca=a[i].lca,gen=a[i].gen,lca1=a[i].lca1;
if(a[i].tag) c[u]-=w,c[v]-=w,c[lca]+=2*w;
else c[gen]-=w,c[rt]+=w,c[lca]-=w,c[hv]-=w,c[lca1]+=2*w,hw-=w;
}
dfs(rt,0);
if(hw<0) flag=1,vis[1]=1;else vis[1]=0;
}
else
{
fq(i,las,x+1)
{
re int u=a[i].u,v=a[i].v,w=a[i].w,lca=a[i].lca,gen=a[i].gen,lca1=a[i].lca1;
if(a[i].tag) c[u]+=w,c[v]+=w,c[lca]-=2*w;
else c[gen]+=w,c[rt]-=w,c[lca]+=w,c[hv]+=w,c[lca1]-=2*w,hw+=w;
}
dfs(rt,0);
if(hw<0) flag=1,vis[1]=1;else vis[1]=0;
}
las=x;
return flag;
}
int main()
{
freopen("eseehc.in","r",stdin);
freopen("eseehc.out","w",stdout);
memset(h,-1,sizeof(h));
SA=gi();SB=gi();SC=gi();n=gi();m=gi();
fp(i,1,m) a[i].u=rng61()%n+1,a[i].v=rng61()%n+1,a[i].w=rng61()%100+1;
fp(i,1,n)
{
re int u=gi(),v=gi(),w=gi();
if(i==1) rt=hu=u,hv=v,hw=w;
else add(u,v,w,i),add(v,u,w,i);
}
dfs1(rt,0);dfs2(rt,rt);
fp(i,1,m)
{
re int u=a[i].u,v=a[i].v;
a[i].tag=(getlca(u,hv)==getlca(v,hv));
if(a[i].tag) a[i].lca=getlca(u,v);
else if(d[getlca(v,hv)]>=d[getlca(u,hv)]) a[i].gen=u,a[i].lca=v,a[i].lca1=getlca(v,hv);
else a[i].gen=v,a[i].lca=u,a[i].lca1=getlca(u,hv);
//printf("%d %d %d %d %d %d\n",u,v,a[i].tag,a[i].lca,getlca(u,hv),getlca(v,hv));
}
re int l=0,r=m+100;
while(l<r)
{
re int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
if(r==m+100) puts("-1");
else
{
check(r);
printf("%d\n",r);
fp(i,1,n) if(vis[i]) printf("%d ",i);
puts("");
}
fclose(stdin);
fclose(stdout);
return 0;
}
注意到几个细节。
可能你在退出二分时,保留的状态是时的状态,导致找不到边权的边。
所以输出答案前要把状态推到答案那一步。
并且将差分标记上传后要清!!!
没调完的表求,期望
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define ls x<<1
#define rs x<<1|1
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e5+100;
unsigned int SA,SB,SC;
int n,m,h[N],cnt,hu,hv,hw,rt,d[N],dd[N],sta[N<<2],top,dp[20][N<<2],f[20][N<<2],id[N],las,flag=0,c[N];
bool vis[N<<1];
struct dat{int u,v,w,tag,lca,gen,lca1;}a[N*100];
struct Edge{int to,nxt,w,id;}e[N<<1];
il void add(re int u,re int v,re ll w,re int id){e[++cnt]=(Edge){v,h[u],w,id};h[u]=cnt;}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
unsigned int rng61()
{
SA^=SA<<16;SA^=SA>>5;SA^=SA<<1;
unsigned int t=SA;
SA=SB;SB=SC;SC^=t^SA;
return SC;
}
il void dfs(re int u,re int fa)
{
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
c[u]+=c[v];
e[i].w+=c[v];
c[v]=0;
if(e[i].w<0) flag=1,vis[e[i].id]=1;else vis[e[i].id]=0;
}
}
il void dfs1(re int u,re int deep)
{
//printf("%d %d\n",u,deep);
id[u]=++top;sta[top]=u;d[top]=deep;dd[u]=deep;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(id[v]) continue;
dfs1(v,deep+1);
sta[++top]=u;d[top]=deep;
}
}
il int getlca(re int l,re int r)
{
l=id[l],r=id[r];
if(l>r) swap(l,r);
re int k=0;
while((1<<k)<=r-l+1) ++k;
--k;
if(f[k][l]<f[k][r-(1<<k)+1]) return dp[k][l];
else return dp[k][r-(1<<k)+1];
}
il int check(re int x)
{
flag=0;
if(las<x)
{
fp(i,las+1,x)
{
re int u=a[i].u,v=a[i].v,w=a[i].w,lca=a[i].lca,gen=a[i].gen,lca1=a[i].lca1;
if(a[i].tag) c[u]-=w,c[v]-=w,c[lca]+=2*w;
else c[gen]-=w,c[rt]+=w,c[lca]-=w,c[hv]-=w,c[lca1]+=2*w,hw-=w;
}
dfs(rt,0);
if(hw<0) flag=1,vis[1]=1;else vis[1]=0;
}
else
{
fq(i,las,x+1)
{
re int u=a[i].u,v=a[i].v,w=a[i].w,lca=a[i].lca,gen=a[i].gen,lca1=a[i].lca1;
if(a[i].tag) c[u]+=w,c[v]+=w,c[lca]-=2*w;
else c[gen]+=w,c[rt]-=w,c[lca]+=w,c[hv]+=w,c[lca1]-=2*w,hw+=w;
}
dfs(rt,0);
if(hw<0) flag=1,vis[1]=1;else vis[1]=0;
}
las=x;
return flag;
}
int main()
{
freopen("eseehc.in","r",stdin);
freopen("eseehc.out","w",stdout);
memset(h,-1,sizeof(h));
SA=gi();SB=gi();SC=gi();n=gi();m=gi();
fp(i,1,m) a[i].u=rng61()%n+1,a[i].v=rng61()%n+1,a[i].w=rng61()%100+1;
fp(i,1,n)
{
re int u=gi(),v=gi(),w=gi();
if(i==1) rt=hu=u,hv=v,hw=w;
else add(u,v,w,i),add(v,u,w,i);
}
dfs1(rt,1);
fp(i,1,top) f[0][i]=d[i],dp[0][i]=sta[i];
for(re int i=1;i<=log(top)/log(2);i++)
for(re int j=1;j<=top-(1<<i)+1;j++)
if(f[i-1][j]<f[i-1][j+(1<<(i-1))]) f[i][j]=f[i-1][j],dp[i][j]=dp[i-1][j];
else f[i][j]=f[i-1][j+(1<<(i-1))],dp[i][j]=dp[i-1][j+(1<<(i-1))];
fp(i,1,m)
{
re int u=a[i].u,v=a[i].v;
a[i].tag=(getlca(u,hv)==getlca(v,hv));
if(a[i].tag) a[i].lca=getlca(u,v);
else if(dd[getlca(v,hv)]>=dd[getlca(u,hv)]) a[i].gen=u,a[i].lca=v,a[i].lca1=getlca(v,hv);
else a[i].gen=v,a[i].lca=u,a[i].lca1=getlca(u,hv);
//printf("%d %d %d %d %d %d\n",u,v,a[i].tag,a[i].lca,getlca(u,hv),getlca(v,hv));
}
re int l=0,r=m+100;
while(l<r)
{
re int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
if(r==m+100) puts("-1");
else
{
check(r);
printf("%d\n",r);
fp(i,1,n) if(vis[i]) printf("%d ",i);
puts("");
}
fclose(stdin);
fclose(stdout);
return 0;
}