luogu2542 航线规划 (树链剖分)

不会lct,所以只能树剖乱搞

一般这种删边的题都是离线倒着做,变成加边

他要求的结果其实就是缩点以后两点间的距离。

然后先根据最后剩下的边随便做出一个生成树,然后假装把剩下的边当成加边操作以后处理

这样的话,就可以做树剖来维护现在的两点间距离。

然后考虑加边,其实就是加了一条边然后某一处成环了,缩成了一个点。

这样的话,就可以把这条边两个端点间的距离都改成0,假装缩了点。

最后再倒着输出答案就行了。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<vector>
  5 #include<queue>
  6 #include<map>
  7 #include<cmath>
  8 #define inf 0x3f3f3f3f
  9 #define LL long long int
 10 using namespace std;
 11 const int maxn=30030,maxm=100010,maxq=40040;
 12
 13 inline LL rd(){
 14     LL x=0;char c=getchar();int neg=1;
 15     while(c<‘0‘||c>‘9‘){if(c==‘-‘) neg=-1;c=getchar();}
 16     while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
 17     return x*neg;
 18 }
 19
 20 struct Edge{
 21     int a,b,ne;bool used,flag;
 22 }eg[maxm*2];
 23 int N,M;
 24 int egh[maxn],ect;
 25 int que[maxq][3],ans[maxq],qct;
 26 int fa[maxn],dep[maxn],wson[maxn],siz[maxn],top[maxn],root[maxn],len[maxn];
 27 int ch[maxn*4][2],val[maxn*4],pct;
 28 bool laz[maxn*4];
 29 map<int,int> mp;
 30
 31 inline void adeg(int a,int b){
 32     eg[ect].a=a;eg[ect].b=b;eg[ect].ne=egh[a];eg[ect].used=1;egh[a]=ect++;
 33 }
 34
 35 inline void pushdown(int p){
 36     if(!laz[p]) return;
 37     val[ch[p][0]]=val[ch[p][1]]=laz[p]=0;
 38     laz[ch[p][0]]=laz[ch[p][1]]=1;
 39 }
 40 inline void update(int p){pushdown(p);val[p]=val[ch[p][0]]+val[ch[p][1]];}
 41
 42 void build(int &p,int l,int r){
 43     p=++pct;
 44     if(l==r) val[p]=1;
 45     else{
 46         int m=l+r>>1;
 47         build(ch[p][0],l,m);build(ch[p][1],m+1,r);
 48         update(p);
 49     }
 50 }
 51
 52 int query(int p,int l,int r,int x,int y){
 53     if(x<=l&&r<=y) return val[p];
 54     else{
 55         pushdown(p);int m=l+r>>1,re=0;
 56         if(x<=m) re+=query(ch[p][0],l,m,x,y);
 57         if(y>=m+1) re+=query(ch[p][1],m+1,r,x,y);
 58         return re;
 59     }
 60 }
 61
 62 void change(int p,int l,int r,int x,int y){
 63     if(x<=l&&r<=y){
 64         val[p]=0;laz[p]=1;pushdown(p);
 65     }else if(val[p]!=0){
 66         pushdown(p);int m=l+r>>1;
 67         if(x<=m) change(ch[p][0],l,m,x,y);
 68         if(y>=m+1) change(ch[p][1],m+1,r,x,y);
 69         update(p);
 70     }
 71 }
 72
 73 void dfs1(int x){
 74     siz[x]=1;int ma=0;
 75     for(int i=egh[x];i!=-1;i=eg[i].ne){
 76         int b=eg[i].b;
 77         if(!eg[i].used||dep[b]) continue;
 78         eg[i].flag=eg[i^1].flag=1;
 79         fa[b]=x;dep[b]=dep[x]+1;
 80         dfs1(b);siz[x]+=siz[b];
 81         if(siz[b]>ma) ma=siz[b],wson[x]=b;
 82     }
 83 }
 84
 85 void dfs2(int x){
 86     if(x!=wson[fa[x]]){int d=0;
 87         for(int i=x;i;i=wson[i]) top[i]=x,d++;
 88         build(root[x],1,d);len[x]=d;
 89     }for(int i=egh[x];i!=-1;i=eg[i].ne){
 90         int b=eg[i].b;
 91         if(eg[i].flag&&fa[x]!=b) dfs2(b);
 92     }
 93 }
 94
 95 void solveC(int x,int y){
 96     while(top[x]!=top[y]){
 97         if(dep[top[x]]<dep[top[y]]) swap(x,y);
 98         change(root[top[x]],1,len[top[x]],1,dep[x]-dep[top[x]]+1);x=fa[top[x]];
 99     }if(x==y) return;
100     if(dep[x]>dep[y]) swap(x,y);
101     change(root[top[x]],1,len[top[x]],dep[x]-dep[top[x]]+2,dep[y]-dep[top[y]]+1);
102 }
103 int solveQ(int x,int y){
104     int re=0;
105     while(top[x]!=top[y]){
106
107         if(dep[top[x]]<dep[top[y]]) swap(x,y);
108         re+=query(root[top[x]],1,len[top[x]],1,dep[x]-dep[top[x]]+1);x=fa[top[x]];
109     }if(x==y) return re;
110     if(dep[x]>dep[y]) swap(x,y);
111     return re+query(root[top[x]],1,len[top[x]],dep[x]-dep[top[x]]+2,dep[y]-dep[top[y]]+1);
112 }
113
114 int main(){
115     int i,j,k;
116     N=rd();M=rd();memset(egh,-1,sizeof(egh));
117     for(i=1;i<=M;i++){
118         int a=rd(),b=rd();
119         mp[a*N+b]=ect;adeg(a,b);
120         mp[b*N+a]=ect;adeg(b,a);
121     }while(++qct){
122         int a=rd();if(a==-1) break;
123         int b=rd(),c=rd();
124         que[qct][0]=a;que[qct][1]=b;que[qct][2]=c;
125         if(!a){
126             int x=mp[b*N+c];
127             eg[x].used=eg[x^1].used=0;
128         }
129     }dep[1]=1;dfs1(1);dfs2(1);
130     for(i=0;i<ect;i++){
131         if((!eg[i].flag)&&eg[i].used) solveC(eg[i].a,eg[i].b);
132     }int act=0;
133     for(i=qct-1;i;i--){
134         if(!que[i][0]) solveC(que[i][1],que[i][2]);
135         else ans[++act]=solveQ(que[i][1],que[i][2]);
136     }for(i=act;i;i--) printf("%d\n",ans[i]);
137     return 0;
138 }

原文地址:https://www.cnblogs.com/Ressed/p/9486223.html

时间: 2024-10-10 07:19:39

luogu2542 航线规划 (树链剖分)的相关文章

Luogu2542 AHOI2005 航线规划 树链剖分、线段树

传送门 看到删边不用想就是反着加边 先把删完边之后的图拆一个生成树出来,然后考虑非树边的影响.实际上非树边就是让树上的一条路径的权值从$1$变为了$0$,而每一个询问就是一条路径上的权值之和.使用树链剖分+线段树维护权值即可. 1 #include<bits/stdc++.h> 2 #define lch (now << 1) 3 #define rch (now << 1 | 1) 4 #define mid ((l + r) >> 1) 5 //This

BZOJ 1969: [Ahoi2005]LANE 航线规划( 树链剖分 )

首先我们要时光倒流, 倒着做, 变成加边操作维护关键边. 先随意搞出一颗树, 树上每条边都是关键边(因为是树, 去掉就不连通了)....然后加边(u, v)时, 路径(u, v)上的所有边都变成非关键边了, 因为形成了环, 环上任意2点有2条路径...下图, 加上蓝色的边, 红色x的边就变成了非关键边. 所以树链剖分维护一下...时间复杂度O(NlogN+MlogM+Qlog^2N), 可以AC. 翻了翻ZY的标解:“动态维护树+最近公共祖先查询”....复杂度是O(NlogN+M+QlogN)

[AHOI2005]航线规划(树链剖分+时间倒流)

传送门 练一下树剖的板子,运用一下时间倒流和下放边权的思想. 题中所谓“关键航线”其实就是桥. 删边操作桥不好维护,但如果是加边,每加一条边,两点作为端点的这条路径就都不再是桥----->考虑时间倒流. 从后往前,每删除一条边,现在就是加边,该路径上所有边都不是桥(打上标记). 可以先求出一棵最小生成树(代码中是在dfs中实现的)那些多的边就以加边的方式加入(说明到最后一个操作后,这条路径的边也不是桥). #include<bits/stdc++.h> #define M 200003

BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]

题意: 一张图,删除边,求两点之间的割边数量.保证任意时刻图连通 任求一棵生成树,只有树边可能是割边 时间倒流,加入一条边,就是两点路径上的边都不可能是割边,区间覆盖... 然后本题需要把边哈希一下,手写哈希比map快很多 貌似还有一种不用树剖的做法,不管了 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; co

bzoj1969 [Ahoi2005]LANE 航线规划 树链剖分

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1969 题解 如果我们把整个图边双联通地缩点,那么最终会形成一棵树的样子. 那么在这棵树上,\(x\) 和 \(y\) 两个点的答案就是它们之间的不在环中的边的数量. 现在考虑动态维护每一条边在不在环中.发现动态删除的话不太好做,所以时光反转,改成插入一条边. 先随便建立一棵生成树,然后如果插入一条非树边,那么两个端点之间的边就都是在环中的边了. 用树剖维护就可以了. 时间复杂度 \(O(q\

【bzoj1959】[Ahoi2005]LANE 航线规划 离线处理+树链剖分+线段树

题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1.2.3……. 一些先遣飞船已经出发,在星球之间开辟探险航线. 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线. 例如下图所示: 在5个星球之间,有5条探险航

[BZOJ2402]陶陶的难题II(树链剖分+线段树维护凸包+分数规划)

陶陶的难题II 时间限制:40s      空间限制:128MB 题目描述 输入格式 第一行包含一个正整数N,表示树中结点的个数. 第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5). 第三行包含N个正实数,第i个数表示yi (1<=yi<=10^5). 第四行包含N个正实数,第i个数表示pi (1<=pi<=10^5). 第五行包含N个正实数,第i个数表示qi (1<=qi<=10^5). 下面有N-1行,每行包含两个正整数a,b(1<

BZOJ 2402 陶陶的难题II 二分答案+斜率优化+树链剖分+线段树维护凸包

题目大意:给定一棵树,每个点有两个坐标(x1,y1)和(x2,y2),多次询问某条链上选择两个点i和j(可以相同),求(y1i+y2j)/(x1i+x2j)的最大值 我竟没看出来这是01分数规划...真是老了... 二分答案ans,问题转化成验证(y1i+y2j)/(x1i+x2j)是否>=ans 将式子变形可得(y1i-ans*x1i)+(y2j-ans*x2j)>=0 加号两边独立,分别计算即可 问题转化为求链上y-ans*x最大的点 令P=y-ans*x 则y=ans*x+P 我们发现这

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In