【BZOJ 4229】 4229: 选择 (线段树+树链剖分)
4229: 选择
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 67 Solved: 41Description
现在,我想知道自己是否还有选择。给定n个点m条边的无向图以及顺序发生的q个事件。每个事件都属于下面两种之一:1、删除某一条图上仍存在的边2、询问是否存在两条边不相交的路径可以从点u出发到点vInput
第一行三个整数n,m,q接下来m行,每行两个整数u,v,表示u和v之间有一条边接下来q行,每行一个大写字母o和2个整数u、v,依次表示按顺序发生的q个事件:当o为’Z’时,表示删除一条u和v之间的边当o为’P’时,表示询问是否存在两条边不相交的路径可以从点u出发到点vOutput
对于每组询问,如果存在,输出Yes,否则输出NoSample Input
7 8 7
1 2
1 3
1 4
2 3
3 4
3 7
7 4
5 6
Z 1 4
P 1 3
P 2 4
Z 1 3
P 1 3
Z 6 5
P 5 6Sample Output
Yes
Yes
No
NoHINT
对于全部数据,max(n,m,q)<=100000Source
【分析】
我的做法跟BZOJ 1969大致一样【我改了改代码交的。。
这题没说删完的图联通,所以最后还要处理一下。。
然后每次询问x到y的关键边数量是否为0就好了。
【详细做法见BZOJ 1969
- #include<cstdio>
- #include<cstdlib>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- using namespace std;
- #define Maxn 100010
- #define Maxm 100010
- struct node
- {
- int x,y,next;
- int bj,id;
- }t[Maxn*],tt[Maxm*];
- int first[Maxn],len;
- void ins(int x,int y)
- {
- // printf("%d -> %d\n",x,y);
- t[++len].x=x;t[len].y=y;
- t[len].next=first[x];first[x]=len;
- }
- struct nnode
- {
- int l,r,lc,rc,sm;
- }tr[Maxn*];
- void upd(int x)
- {
- if(tr[x].l==tr[x].r||tr[x].sm!=) return;
- int lc=tr[x].lc,rc=tr[x].rc;
- tr[lc].sm=tr[rc].sm=;
- }
- int tot;
- int build(int l,int r)
- {
- int x=++tot;
- tr[x].l=l;tr[x].r=r;
- if(l!=r)
- {
- int mid=(l+r)>>;
- tr[x].lc=build(l,mid);
- tr[x].rc=build(mid+,r);
- }
- else tr[x].lc=tr[x].rc=;
- tr[x].sm=r-l+;
- return x;
- }
- void change(int x,int l,int r)
- {
- if(tr[x].l==l&&tr[x].r==r)
- {
- tr[x].sm=;
- return;
- }
- upd(x);
- int mid=(tr[x].l+tr[x].r)>>,lc=tr[x].lc,rc=tr[x].rc;
- if(r<=mid) change(lc,l,r);
- else if(l>mid) change(rc,l,r);
- else
- {
- change(lc,l,mid);
- change(rc,mid+,r);
- }
- tr[x].sm=tr[lc].sm+tr[rc].sm;
- }
- int query(int x,int l,int r)
- {
- if(tr[x].sm==) return ;
- if(tr[x].l==l&&tr[x].r==r) return tr[x].sm;
- upd(x);
- int mid=(tr[x].l+tr[x].r)>>,lc=tr[x].lc,rc=tr[x].rc;
- if(r<=mid) return query(lc,l,r);
- else if(l>mid) return query(rc,l,r);
- else return query(lc,l,mid)+query(rc,mid+,r);
- }
- int tp[Maxn],sum[Maxn],son[Maxn],dfn[Maxn],dep[Maxn];
- int ff[Maxn];
- int cnt;
- void dfs(int x,int f)
- {
- son[x]=;sum[x]=;dep[x]=dep[f]+;
- ff[x]=f;
- for(int i=first[x];i;i=t[i].next) if(t[i].y!=f)
- {
- int y=t[i].y;
- dfs(y,x);
- sum[x]+=sum[y];
- if(son[x]==||sum[son[x]]<sum[y]) son[x]=y;
- }
- }
- void dfs2(int x,int tpp)
- {
- dfn[x]=++cnt;tp[x]=tpp;
- if(son[x]) dfs2(son[x],tpp);
- for(int i=first[x];i;i=t[i].next) if(t[i].y!=ff[x]&&t[i].y!=son[x])
- {
- int y=t[i].y;
- dfs2(y,y);
- }
- }
- void fchange(int x,int y)
- {
- while(tp[x]!=tp[y])
- {
- if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
- change(,dfn[tp[x]],dfn[x]);
- x=ff[tp[x]];
- }
- if(dep[x]<dep[y]) swap(x,y);
- if(x!=y) change(,dfn[y]+,dfn[x]);
- }
- int fquery(int x,int y)
- {
- int ans=;
- while(tp[x]!=tp[y])
- {
- if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
- ans+=query(,dfn[tp[x]],dfn[x]);
- x=ff[tp[x]];
- }
- if(dep[x]<dep[y]) swap(x,y);
- if(x!=y)
- {
- // if(dfn[y]+1>dfn[x]) while(1);
- ans+=query(,dfn[y]+,dfn[x]);
- }
- return ans;
- }
- int fa[Maxn];
- int ffa(int x)
- {
- if(fa[x]!=x) fa[x]=ffa(fa[x]);
- return fa[x];
- }
- bool cmp(node x,node y)
- {
- if(x.x==y.x&&x.y==y.y) return x.bj<y.bj;
- return (x.x==y.x)?(x.y<y.y):(x.x<y.x);
- }
- bool cmp2(node x,node y) {return x.id<y.id;}
- int ans[Maxn];
- char s[];
- void solve()
- {
- int n,m,q;
- scanf("%d%d%d",&n,&m,&q);
- int ll=;
- for(int i=;i<=m;i++)
- {
- int x,y;
- ll++;
- scanf("%d%d",&tt[ll].x,&tt[ll].y);
- if(tt[ll].x>tt[ll].y) swap(tt[ll].x,tt[ll].y);
- tt[ll].bj=;//cha ru
- }
- int ct=;
- while(q--)
- {
- scanf("%s",s);
- ll++;
- scanf("%d%d",&tt[ll].x,&tt[ll].y);
- if(tt[ll].x>tt[ll].y) swap(tt[ll].x,tt[ll].y);
- if(s[]=='Z') tt[ll].bj=-;//shan chu
- else tt[ll].bj=;//xun wen
- tt[ll].id=++ct;
- }
- sort(tt+,tt++ll,cmp);
- for(int i=;i<=n;i++) fa[i]=i;
- ct++;
- int pp=;
- for(int i=;i<=ll;i++)
- {
- if(tt[i].bj==) continue;
- if(tt[i].bj==)
- {
- if(pp==||tt[i].x!=tt[pp].x||tt[i].y!=tt[pp].y)
- {
- if(ffa(tt[i].x)==ffa(tt[i].y))
- {
- tt[i].bj=-;
- tt[i].id=ct;
- }
- else
- {
- ins(tt[i].x,tt[i].y);
- ins(tt[i].y,tt[i].x);
- fa[ffa(tt[i].x)]=tt[i].y;
- }
- }
- }
- pp=i;
- }
- sort(tt+,tt++ll,cmp2);
- for(int i=ll;i>=;i--) if(tt[i].bj==-)
- {
- if(ffa(tt[i].x)!=ffa(tt[i].y))
- {
- ins(tt[i].x,tt[i].y);
- ins(tt[i].y,tt[i].x);
- fa[ffa(tt[i].x)]=tt[i].y;
- tt[i].bj=;
- }
- }
- dep[]=;cnt=;
- for(int i=;i<=n;i++) if(ffa(i)==i)
- {
- dfs(i,);
- dfs2(i,i);
- }
- build(,n);
- ans[]=;
- for(int i=ll;i>=;i--)
- {
- if(tt[i].bj==) continue;
- if(tt[i].bj==-)
- {
- fchange(tt[i].x,tt[i].y);
- }
- else
- {
- if(ffa(tt[i].x)!=ffa(tt[i].y)) ans[++ans[]]=-;
- else ans[++ans[]]=fquery(tt[i].x,tt[i].y);
- }
- }
- for(int i=ans[];i>=;i--)
- {
- if(ans[i]==) printf("Yes\n");
- else printf("No\n");
- }
- }
- int main()
- {
- solve();
- return ;
- }
【是不是打的有点丑
2017-03-27 10:33:13
【BZOJ 4229】 4229: 选择 (线段树+树链剖分)的更多相关文章
- 线段树&数链剖分
傻逼线段树,傻逼数剖 线段树 定义: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 使用线段树可以快速的查找某一个节点在若干条线段中出现 ...
- UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...
- BZOJ1758[Wc2010]重建计划——分数规划+长链剖分+线段树+二分答案+树形DP
题目描述 输入 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai, ...
- [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分
题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...
- CF487E Tourists 圆方树、树链剖分
传送门 注意到我们需要求的是两点之间所有简单路径中最小值的最小值,那么对于一个点双联通分量来说,如果要经过它,则一定会经过这个点双联通分量里权值最小的点 注意:这里不能缩边双联通分量,样例\(2\)就 ...
- BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)
题意 自己看. 分析 求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做. 先对树长链剖分. ...
- 2019.01.08 codeforces 1009F. Dominant Indices(长链剖分)
传送门 长链剖分模板题. 题意:给出一棵树,设fi,jf_{i,j}fi,j表示iii的子树中距离点iii距离为jjj的点的个数,现在对于每个点iii要求出使得fif_ifi取得最大值的那个jjj ...
- 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)
LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )
s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...
随机推荐
- html跑马灯效果
实现跑马灯的方法很多,其中最简单的是采用一句Html代码来实现,我们在需要出现跑马灯效果的地方插入“<marquee>滚动的文字</marquee>”语句,它的效果如下所示: ...
- HDU 2044 Coins
有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数. 其中,蜂房的结构如下所示. Input输入数据的第一行是一个整数N,表示测试实例的个数,然 ...
- 在Unity中实现屏幕空间反射Screen Space Reflection(4)
第四部分讲一下如何在2D屏幕空间步进光线. http://casual-effects.blogspot.com/2014/08/screen-space-ray-tracing.html 中的代码感 ...
- 多进程Process
多进程旧式写法 from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': p = Pool(5) ...
- TinyOS 代码分析
1.Basestation案例 位于/opt/tinyos-main-master/apps/Basetation 1.1本例的顶层结构图: 1.2软件实现流程 1) uartIn,uartOut ...
- python设计模式之迭代器与生成器详解(五)
前言 迭代器是设计模式中的一种行为模式,它提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示.python提倡使用生成器,生成器也是迭代器的一种. 系列文章 python设计模 ...
- [003] largest_subarray_with_equal_1&0
[Description] Given an array with only '1' and '0', find a largest length sub-array which contains e ...
- iTextSharp之pdfRead(两个文件文本内容的比较,指定页数的pdf截取,水印的添加)
using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.text.pdf.parser; using System; us ...
- linux系统查找具体进程
ps -ef | grep '查找内容' eg:ps -ef | grep '测试USB设备穿透'
- Enumeration的学习
枚举是jdk5.0之后的新特性.枚举的使用在编程中能起到很大的作用,本文从枚举的适用范围.枚举的特点.枚举的使用等三个方面学习枚举 一.枚举的使适用范围 “在有限的范围内选择值”:比如一个星期只有星期 ...