您的位置:首页 > 其它

[bzoj1969][AHOI2005]LANE 航线规划

2016-08-18 21:44 411 查看

题目大意

一个n个节点m条边的图,两点间的关键边定义为从一点走到另一个点必须经过的边。

现有许多操作,删一条边或者询问两点间的关键边数量。

保证任意时刻原图联通。

时间倒流

先把所有边删掉,然后倒着做,转删边为加边。

然后我们思考,最后原图也是联通的,那么做边双联通分量缩点后,就会变成一棵树。

然后显然两个结点间关键边数等于它们所处联通分量代表的点在树上树路径的边数。

然而我们要处理加边,每加一条边产生一个环,例如j与k(j与k指树中节点)间添加一条边,那么j到k路径上的所有点都处在一个环中,自然的,j到k路径上的所有边绝对不可能是关键边。

于是边给个边权,1代表是关建边0代表不是。

询问就是询问树中路径边权和,树链剖分维护。

修改就是路径上的边都赋值为0。

注意各种细节。。

怎么我代码那么丑写了230+行,陈主力比我少100行。

#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second
using namespace std;
typedef pair<int,int> suan;
map<suan,int> pos,sop;
const int maxn=30000+10,maxm=100000+10;
int fa[maxn][20],d[maxn];
int h[maxn],belong[maxn],s[maxn],dfn[maxn],low[maxn],from[maxm*2],go[maxm*2],next[maxm*2];
int size[maxn],jump[maxn];
int h2[maxn],g2[maxn*2],n2[maxn*2];
int q[maxn*2][4];
int tree[maxn*4],set[maxn*4];
bool bz[maxm],zb[maxm],pd[maxn],flag[maxn],bj[maxn*4];
int i,j,k,l,t,n,m,tot,top,cnt,num,sum,euler;
void add(int x,int y){
pos[make_pair(x,y)]=++tot;
go[tot]=y;
from[tot]=x;
next[tot]=h[x];
h[x]=tot;
}
void add2(int x,int y){
g2[++sum]=y;
n2[sum]=h2[x];
h2[x]=sum;
}
void tarjan(int x){
dfn[x]=low[x]=++euler;
s[++top]=x;
pd[x]=1;
flag[x]=1;
int t=h[x];
while (t){
if (!bz[(t+1)/2]&&!zb[(t+1)/2]){
zb[(t+1)/2]=1;
if (pd[go[t]]){
if (flag[go[t]]) low[x]=min(low[x],dfn[go[t]]);
}
else{
tarjan(go[t]);
low[x]=min(low[x],low[go[t]]);
}
}
t=next[t];
}
if (dfn[x]==low[x]){
num++;
do{
belong[s[top]]=num;
flag[s[top]]=0;
top--;
}while (s[top+1]!=x);
}
}
void dfs(int x,int y){
fa[x][0]=y;
d[x]=d[y]+1;
int t=h2[x];
size[x]=1;
while (t){
if (g2[t]!=y){
dfs(g2[t],x);
size[x]+=size[g2[t]];
}
t=n2[t];
}
}
void dg(int x,int y){
dfn[x]=++euler;
int t=h2[x],j=0;
while (t){
if (g2[t]!=y&&(j==0||size[g2[t]]>size[j])) j=g2[t];
t=n2[t];
}
if (j){
jump[j]=jump[x];
dg(j,x);
}
t=h2[x];
while (t){
if (g2[t]!=y&&g2[t]!=j){
jump[g2[t]]=g2[t];
dg(g2[t],x);
}
t=n2[t];
}
}
int lca(int x,int y){
if (d[x]<d[y]) swap(x,y);
if (d[x]!=d[y]){
int j=floor(log(num)/log(2));
while (j>=0){
if (d[fa[x][j]]>=d[y]) x=fa[x][j];
j--;
}
}
if (x==y) return x;
int j=floor(log(num)/log(2));
while (j>=0){
if (fa[x][j]!=fa[y][j]){
x=fa[x][j];
y=fa[y][j];
}
j--;
}
return fa[x][0];
}
void mark(int p,int l,int r,int v){
tree[p]=(r-l+1)*v;
bj[p]=1;
set[p]=v;
}
void down(int p,int l,int r){
int mid=(l+r)/2;
if (bj[p]){
mark(p*2,l,mid,set[p]);
mark(p*2+1,mid+1,r,set[p]);
bj[p]=0;
}
}
void change(int p,int l,int r,int a,int b,int v){
if (l==a&&r==b){
mark(p,l,r,v);
return;
}
down(p,l,r);
int mid=(l+r)/2;
if (b<=mid) change(p*2,l,mid,a,b,v);
else if (a>mid) change(p*2+1,mid+1,r,a,b,v);
else{
change(p*2,l,mid,a,mid,v);
change(p*2+1,mid+1,r,mid+1,b,v);
}
tree[p]=tree[p*2]+tree[p*2+1];
}
int query(int p,int l,int r,int a,int b){
if (l==a&&r==b) return tree[p];
down(p,l,r);
int mid=(l+r)/2;
if (b<=mid) return query(p*2,l,mid,a,b);
else if (a>mid) return query(p*2+1,mid+1,r,a,b);
else return query(p*2,l,mid,a,mid)+query(p*2+1,mid+1,r,mid+1,b);
}
int main(){
freopen("data.in","r",stdin);freopen("data.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,m){
scanf("%d%d",&j,&k);
add(j,k);
add(k,j);
}
while (1){
scanf("%d",&q[++cnt][0]);
if (q[cnt][0]==-1) break;
scanf("%d%d",&q[cnt][1],&q[cnt][2]);
if (!q[cnt][0]) bz[(pos[make_pair(q[cnt][1],q[cnt][2])]+1)/2]=1;
}
cnt--;
tarjan(1);
fo(i,1,tot)
if (!bz[(i+1)/2]&&belong[from[i]]!=belong[go[i]]){
j=belong[from[i]];k=belong[go[i]];
if (j>k) swap(j,k);
if (!sop[make_pair(j,k)]){
sop[make_pair(j,k)]=1;
add2(j,k);
add2(k,j);
}
}
dfs(1,0);
fo(j,1,floor(log(num)/log(2)))
fo(i,1,num)
fa[i][j]=fa[fa[i][j-1]][j-1];
euler=0;
dg(1,0);
fo(i,2,num) change(1,1,num,dfn[i],dfn[i],1);
fd(i,cnt,1){
j=belong[q[i][1]];k=belong[q[i][2]];
if (j==k) continue;
l=lca(j,k);
if (q[i][0]==0){
while (j!=l){
if (d[jump[j]]<=d[l]){
change(1,1,num,dfn[l]+1,dfn[j],0);
j=l;
}
else{
change(1,1,num,dfn[jump[j]],dfn[j],0);
j=fa[jump[j]][0];
}
}
while (k!=l){
if (d[jump[k]]<=d[l]){
change(1,1,num,dfn[l]+1,dfn[k],0);
k=l;
}
else{
change(1,1,num,dfn[jump[k]],dfn[k],0);
k=fa[jump[k]][0];
}
}
}
else{
while (j!=l){
if (d[jump[j]]<=d[l]){
q[i][3]+=query(1,1,num,dfn[l]+1,dfn[j]);
j=l;
}
else{
q[i][3]+=query(1,1,num,dfn[jump[j]],dfn[j]);
j=fa[jump[j]][0];
}
}
while (k!=l){
if (d[jump[k]]<=d[l]){
q[i][3]+=query(1,1,num,dfn[l]+1,dfn[k]);
k=l;
}
else{
q[i][3]+=query(1,1,num,dfn[jump[k]],dfn[k]);
k=fa[jump[k]][0];
}
}
}
}
fo(i,1,cnt)
if (q[i][0]) printf("%d\n",q[i][3]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: