[UOJ30/Codeforces Round #278 E]Tourists
好毒瘤的一道题QAQ,搞了好几好几天。
UOJ上卡在了53个点,CF上过了,懒得优化常数了
刚看时一眼Tarjan搞个强连通分量然后缩点树链剖分xjb搞搞就行了,然后写完了,然后WA了QAQ。
思考了一会把代码全删了,加了个mulutiset重写一遍,然后又是各种WA。
然后去看了POPOQQQ大爷的代码。原来把无向图缩成一个树用的是点双联通分量,搞不清图论的概念只能自扇脸..
然后去研究了点双联通分量,搞了一道题,顺便给Trajn搞了个小总结。
这道题其实就是缩点然后剖剖剖。但是我的姿势不太对,而且中间也有一些细节。
先点双缩成一颗树,然后对于每个点双新建一虚点,点双中的每个割点向虚点连边。这样最好形成的树的每一条路径就一定是 虚点-割点-虚点-割点.....
剩下的任务是不是就是敲剖分的模板了?
并不是hhh。考虑修改操作,每次修改的如果非割点,更新这个点所在的点双就行了也就是树中的虚点。但是如果修改的点是割点的话,就需要更新这个割点所连接的每个点双,因为一个割点可以属于多个点双。如果出题人给你搞个菊花图你就GG了。
PS.对于修改操作,需要用STL里的$multiset$,代码如下:
struct BCC{ int v;msi s; inline void insert(int num){s.insert(num);v=*s.begin();} inline void change(int x,int y){s.erase(s.find(x));s.insert(y);v=*s.begin();} }bcc[MAXN];
换个思路,如果更新割点需要更新所连接的每个点双,那么在查询一个点双的时候是否可以顺便查询他的父亲(必为割点)?
所以在查询的时候,如果当前点是虚点,再查询一下父亲就OK了。
//UOJ 30 Fuck this problem //by Cydiater //2016.11.1 #include <iostream> #include <iomanip> #include <map> #include <set> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <ctime> #include <bitset> #include <queue> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) #define cmax(a,b) a=max(a,b) #define cmin(a,b) a=min(a,b) #define Auto(i,node) for(int i=LINK[node];i;i=e[i].next) #define msi multiset<int> const int MAXN=2e5+5; const int oo=0x3f3f3f3f; inline int read(){ char ch=getchar();int x=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int N,M,Q,Val[MAXN],stack[MAXN],top=0,dfn[MAXN],low[MAXN],dfs_clock=0,group[MAXN],group_num=0,fa[MAXN][25],dep[MAXN],son[MAXN],siz[MAXN],Pos[MAXN],Top[MAXN],val[MAXN],cnt=0; int t[MAXN<<3],k,v,L,R,LEN=0; bool iscut[MAXN]; char opt; struct edge{int x,y,next;}u[MAXN<<1]; struct BCC{ int v;msi s; inline void insert(int num){s.insert(num);v=*s.begin();} inline void change(int x,int y){s.erase(s.find(x));s.insert(y);v=*s.begin();} }bcc[MAXN]; inline void Inserter(int x,int y){u[++LEN].x=x;u[LEN].y=y;} struct Graph{ int LINK[MAXN],len; edge e[MAXN<<2]; inline void insert(int x,int y){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;} inline void Insert(int x,int y){insert(x,y);insert(y,x);} void tarjan(int node){ dfn[node]=low[node]=++dfs_clock; stack[++top]=node; Auto(i,node)if(!dfn[e[i].y]){ tarjan(e[i].y); cmin(low[node],low[e[i].y]); if(low[e[i].y]>=dfn[node]){ group_num++;int tmp;iscut[node]=1; do{ tmp=stack[top--]; group[tmp]=group_num; if(iscut[tmp])Inserter(tmp+N,group_num); }while(tmp!=e[i].y); Inserter(node+N,group_num); } }else cmin(low[node],dfn[e[i].y]); } void dfs1(int node,int deep,int father){ dep[node]=deep;fa[node][0]=father;son[node]=0; int max_siz=0;siz[node]=1; Auto(i,node)if(e[i].y!=father){ dfs1(e[i].y,deep+1,node); if(siz[e[i].y]>max_siz){ max_siz=siz[e[i].y]; son[node]=e[i].y; } } } void dfs2(int node,int tp){ Top[node]=tp;Pos[node]=++cnt;val[cnt]=bcc[node].v; if(son[node])dfs2(son[node],tp); Auto(i,node)if(e[i].y!=fa[node][0]&&e[i].y!=son[node]) dfs2(e[i].y,e[i].y); } int LCA(int x,int y){ if(x==y) return x; if(dep[x]<dep[y])swap(x,y); down(i,18,0)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i]; if(x==y) return x; down(i,18,0)if(fa[x][i]!=0&&fa[x][i]!=fa[y][i]){ x=fa[x][i];y=fa[y][i]; } return fa[x][0]; } }G1,G2; namespace solution{ inline void reload(int root){t[root]=min(t[root<<1],t[root<<1|1]);} void init(){ N=read();M=read();Q=read(); up(i,1,N)Val[i]=read(); up(i,1,M){ int x=read(),y=read(); G1.Insert(x,y); } } void build(int leftt,int rightt,int root){ if(leftt==rightt){t[root]=val[leftt];return;} int mid=(leftt+rightt)>>1; build(leftt,mid,root<<1); build(mid+1,rightt,root<<1|1); reload(root); } inline void updata(int leftt,int rightt,int root){ if(leftt==rightt){ t[root]=v;return; } int mid=(leftt+rightt)>>1; if(k>mid)updata(mid+1,rightt,root<<1|1); if(k<=mid)updata(leftt,mid,root<<1); reload(root); } inline int Get(int leftt,int rightt,int root){ if(leftt>=L&&rightt<=R) return t[root]; int mid=(leftt+rightt)>>1; if(L>=mid+1) return Get(mid+1,rightt,root<<1|1); else if(R<=mid) return Get(leftt,mid,root<<1); else return min(Get(leftt,mid,root<<1),Get(mid+1,rightt,root<<1|1)); } inline int get(int node,int lca){ int ans=oo; while(Top[node]!=Top[lca]){ L=Pos[Top[node]];R=Pos[node]; cmin(ans,Get(1,cnt,1)); node=fa[Top[node]][0]; } L=Pos[lca];R=Pos[node]; cmin(ans,Get(1,cnt,1)); return ans; } void get_ancestor(){ up(i,1,20)up(node,1,N<<1)if(fa[node][i-1]) fa[node][i]=fa[fa[node][i-1]][i-1]; } void slove(){ memset(iscut,0,sizeof(iscut)); G1.tarjan(1); up(i,1,LEN){ int x=u[i].x,y=u[i].y; G2.Insert(x,y); } up(i,1,N){ if(i!=1)bcc[group[i]].insert(Val[i]); if(iscut[i])bcc[i+N].insert(oo); } G2.dfs1(N+1,0,0);G2.dfs2(N+1,N+1); build(1,cnt,1);get_ancestor(); while(Q--){ scanf("%c",&opt); if(opt=='C'){ int x=read(),y=read(); if(x!=1){ bcc[group[x]].change(Val[x],y); k=Pos[group[x]];v=bcc[group[x]].v; updata(1,cnt,1); } Val[x]=y; }else{ int x=read(),y=read(); if(x==y){ printf("%d\n",Val[x]); continue; } x=iscut[x]?x+N:group[x]; y=iscut[y]?y+N:group[y]; int lca=G2.LCA(x,y),ans=oo; if(lca<=group_num)lca=fa[lca][0]; ans=Val[lca-N]; cmin(ans,min(get(x,lca),get(y,lca))); printf("%d\n",ans); } } } } int main(){ //freopen("input.in","r",stdin); using namespace solution; init(); slove(); return 0; }
[UOJ30/Codeforces Round #278 E]Tourists的更多相关文章
- UOJ30——【CF Round #278】Tourists
1.感谢taorunz老师 2.题目大意:就是给个带权无向图,然后有两种操作, 1是修改某个点的权值 2是询问,询问一个值,就是u到v之间经过点权的最小值(不可以经过重复的点) 操作数,点数,边数都不 ...
- uoj30【CF Round #278】Tourists(圆方树+树链剖分+可删除堆)
- 学习了一波圆方树 学习了一波点分治 学习了一波可删除堆(巧用 ? STL) 传送门: Icefox_zhx 注意看代码看怎么构建圆方树的. tips:tips:tips:圆方树内存记得开两倍 CO ...
- Codeforces Round #278 (Div. 2)
题目链接:http://codeforces.com/contest/488 A. Giga Tower Giga Tower is the tallest and deepest building ...
- Brute Force - B. Candy Boxes ( Codeforces Round #278 (Div. 2)
B. Candy Boxes Problem's Link: http://codeforces.com/contest/488/problem/B Mean: T题目意思很简单,不解释. ana ...
- Codeforces Round #278 (Div. 1) B. Strip multiset维护DP
B. Strip Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/487/problem/B De ...
- Codeforces Round #278 (Div. 1) A. Fight the Monster 暴力
A. Fight the Monster Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/487/ ...
- CodeForces Round #278 (Div.2) (待续)
A 这么简单的题直接贴代码好了. #include <cstdio> #include <cmath> using namespace std; bool islucky(in ...
- Codeforces Round #278 (Div. 1)
A A monster is attacking the Cyberland! Master Yang, a braver, is going to beat the monster. Yang an ...
- UOJ #30. 【CF Round #278】Tourists
Description Cyberland 有 n 座城市,编号从 1 到 n,有 m 条双向道路连接这些城市.第 j 条路连接城市 aj 和 bj.每天,都有成千上万的游客来到 Cyberland ...
随机推荐
- Linux SSH登录慢案例分析
手头有台Linux服务器ssh登录时超级慢,需要几十秒.其它服务器均没有这个问题.平时登录操作都默默忍了.今天终于忍不住想搞清楚到底什么原因.搜索了一下发现了很多关于ssh登录慢的资料,于是自己也学着 ...
- .NET架构设计、框架设计系列文章总结
从事.NET开发到现在已经有七个年头了.慢慢的可能会很少写.NET文章了.不知不觉竟然走了这么多年,热爱.NET热爱c#.突然想对这一路的经历进行一个总结. 是时候开始下一阶段的旅途,希望这些文章可以 ...
- sql server 里面的 dynamic Data Masking
有时候啊,当我们存放在数据库里面的数据,需要明文存放,但是对于前台查询出来的,又不太希望明文放出去的时候(比方说客户的手机啊,邮箱啊)之类有点敏感的信息,之前通常是保存个明文,然后在前台展现的时候再特 ...
- stl之截取:以一段字符串截取字符串
string dforder = line.substr(0,line.find("\t")).c_str(); 解析: line为传进来的string类型 substr查找第0位 ...
- [Java入门笔记] Java语言基础(五):数组
简介 数组可用用于存储存储多个数据,Java的数组要求所有的数组元素具有一种相同的数据类型.一旦数组初始化完成,数组在内存中的空间被固定下来,长度不可改变,即使把数组的元素清空,所占用的空间依然被保留 ...
- 读《高性能javascript》笔记(一)
第一章加载与执行:1,js脚本会阻塞页面渲染,<script>尽可能放到<body>标签的底部2, 合并脚本,页面中的<script>标签越少:HTTP请求带来的额 ...
- WPFTookit Chart 高级进阶
数据源增加SeriesSource 使用方式 <Charting:Chart x:Name="chart" Helper:ChartHelper.DependentValue ...
- 在Azure上实现Linux Server故障转移
要充分利用公有云的弹性扩展和高可用, 首先要在应用系统层面支持横向扩展(scale out),这个说起来很容易,或者说对新开发的应用系统而言已经成为标配.但是对已有的.老旧的应用系统来说,这就比较困难 ...
- Serial Port Programming on Linux(转载)
This is a tutorial on how to program the Serial Ports on your Linux box.Serial Ports are nice little ...
- SQLMAP参数介绍
转自:http://zhan.renren.com/bugpower?gid=3602888498044629629&checked=true SQLMAP参数介绍 sqlmap的使用方式:p ...