题目大意

给定一棵基环外向树,和若干组询问,对于每次独立的询问都指定一些起点和一些终点,你删去一些边,使得从任意起点出发都无法到达终点,并让删去的边的编号的最小值最大,求这个最大的最小值。

题解

不难发现,在基环外向树中,任意两个点之间至多有唯一条简单路径,且对于这道题来讲非简单路径是没有意义的,因为非简单路径一定会囊括一个简单路径。这意味着对于每一个终点,至多有一个与之对应的距离最短的起点,使得当你将这条路径上某一条边删掉时,这个起点就不可能被到达了。那么我们显然会贪心的删去路径上编号最大的那一条。由于每一个点的入边(如果有的话)是唯一的,且没有修改操作,我们就可以用倍增来求路径最大值。

现在问题就转化为如何找每个重点对应的起点,我们分开考虑。

先考虑起点仅通过树边到达终点的情况。这个比较好办,将所有起点按照深度从小到大依次处理,每次把当前起点的深度当做标记覆盖到以这一起点所代表的的子树中,这个用线段树处理即可。做完这件事以后,扫一遍终点,如果它已经被覆盖到了,那么就通过标记和深度直接算出起点和终点的距离,倍增求一下最大值,最终答案取$\min$,然后把这个终点删掉即可。

剩下的终点一定满足没有一个起点能够仅通过树边到达,所以必须通过一部分环上的边,因而不在环上的起点也没用了,删掉即可。我们直接让剩下的终点先跳到它们所在的树的树根上,并在路径上的边求编号的$\max$,如果树根不在环上或树根所在的环上没有任何起点,那么这个中点本身就不可被任何起点到达,对答案没有贡献。然后对于每一个环,将起点和终点都按照顺时针排序,枚举每一个终点都一定能找到它的前驱起点,更新答案即可。

复杂度$O(N+\sum\limits_{i=1}^{m} (t_i+f_i)\log N)$

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 200020
#define mid ((l+r)>>1)
using namespace std;
const int BufferSize=1<<19;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
if(head==tail) {
int l=fread(buffer,1,BufferSize,stdin);
tail=(head=buffer)+l;
} return *head++;
}
int read(){
int nm=0,fh=1; char cw=Getchar();
for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
int n,m,fs[M],fa[M][19],t[M][19],tmp=1,dfn[M],sz[M],od[M],to[M],nt[M];
int cnt,id[M],dep[M],tg[M<<2],maxn,tp[M],CT[M];
int S1[M],S2[M],C1[M],C2[M];
bool cir[M],vis[M],ist[M];
void link(int x,int y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
void dfs(int x){
sz[x]=1,dfn[x]=++cnt,vis[x]=true;
for(int i=fs[x];i!=-1;i=nt[i]){
if(cir[to[i]]) continue; id[to[i]]=id[x];
dep[to[i]]=dep[x]+1,tp[to[i]]=tp[x];
dfs(to[i]),sz[x]+=sz[to[i]];
}
}
bool cmpd(int x,int y){return dep[x]<dep[y];}
bool cmpc(int x,int y){if(id[tp[x]]!=id[tp[y]]) return id[tp[x]]<id[tp[y]];return od[tp[x]]>od[tp[y]];}
void pushdown(int x){if(tg[x]!=-1) tg[x<<1]=tg[x<<1|1]=tg[x],tg[x]=-1;}
void upd(int x,int l,int r,int L,int R,int D){
if(r<L||R<l) return;
if(L<=l&&r<=R){tg[x]=D;return;}
pushdown(x),upd(x<<1,l,mid,L,R,D),upd(x<<1|1,mid+1,r,L,R,D);
}
int qry(int x,int l,int r,int pos){
if(l==r) return tg[x]; pushdown(x);
if(pos<=mid) return qry(x<<1,l,mid,pos); return qry(x<<1|1,mid+1,r,pos);
}
int dp(int x,int dt){
int res=0;
for(int k=0;dt>0;k++,dt>>=1) if(dt&1) res=max(res,t[x][k]),x=fa[x][k];
return !res?m+1:res;
}
int main(){
n=read(),m=read(),memset(fs,-1,sizeof(fs));
for(int i=1;i<=m;i++){int u=read(),v=read();fa[v][0]=u,t[v][0]=i,link(u,v);}
for(int i=1;i<=n;i++){
if(vis[i]) continue; int now;
for(vis[now=i]=true;fa[now][0]&&!vis[fa[now][0]];now=fa[now][0]) vis[fa[now][0]]=true;
if(!fa[now][0]){
ist[now]=true,t[now][0]=0;
id[now]=++maxn,tp[now]=now,dfs(now); continue;
}
for(maxn++;!cir[now];now=fa[now][0]){
cir[now]=true,id[now]=maxn,tp[now]=now;
od[fa[now][0]]=od[now]+1,CT[maxn]++;
} dfs(now);
for(now=fa[now][0];od[now]!=CT[maxn];now=fa[now][0]) dfs(now);
}
for(int k=1;k<19;k++){
for(int i=1;i<=n;i++){
fa[i][k]=fa[fa[i][k-1]][k-1];
t[i][k]=max(t[i][k-1],t[fa[i][k-1]][k-1]);
}
}
for(int Qs=read();Qs;--Qs){
upd(1,1,n,1,n,-2);
int now,m1=read(),m2,st=1,ed=1,ans=m+1,n1=0,n2=0,ps=1;
for(int i=1;i<=m1;i++) S1[i]=read(); m2=read();
for(int i=1;i<=m2;i++) S2[i]=read(); sort(S1+1,S1+m1+1,cmpd);
for(int i=1;i<=m1;i++) upd(1,1,n,dfn[S1[i]],dfn[S1[i]]+sz[S1[i]]-1,dep[S1[i]]);
for(int i=1;i<=m2;i++){
if(!dep[S2[i]]){if(cir[tp[S2[i]]]) C2[++n2]=S2[i];continue;}
int num=qry(1,1,n,dfn[S2[i]]),cst;
if(num>=0) cst=dp(S2[i],dep[S2[i]]-num),ans=min(ans,cst);
else C2[++n2]=S2[i];
}
for(int i=1;i<=m1;i++) if(cir[S1[i]]) C1[++n1]=S1[i];
sort(C1+1,C1+n1+1,cmpc),sort(C2+1,C2+n2+1,cmpc),C1[n1+1]=C2[n2+1]=0;
for(int i=1;i<=n2;i++){
while(ed<n1&&id[C1[st]]<id[tp[C2[i]]]) st=ed+1,ed=ps=st;
if(id[C1[st]]<id[tp[C2[i]]]) break;
if(id[C1[st]]>id[tp[C2[i]]]) continue;
while(ed<n1&&id[C1[st]]==id[C1[ed+1]]) ed++;
now=cir[C2[i]]?0:dp(C2[i],dep[C2[i]]),C2[i]=tp[C2[i]];
while(ps<ed&&od[C1[ps+1]]>od[C2[i]]) ps++;
if(od[C1[ps]]>od[C2[i]]) now=max(now,dp(C2[i],od[C1[ps]]-od[C2[i]]));
else now=max(now,dp(C2[i],CT[id[C1[ps]]]+od[C1[ed]]-od[C2[i]]));
if(now) ans=min(ans,now);
}
if(ans==m+1) puts("OK"); else printf("%d\n",ans);
}
return 0;
}

  

Statement的更多相关文章

  1. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):

    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): da.huying.usermanag ...

  2. [解决方案]CREATE DATABASE statement not allowed within multi-statement transaction.

    CREATE DATABASE statement not allowed within multi-statement transaction. 刚开始报这个错误的时候,我上度娘搜了一下. 别人是在 ...

  3. Drop all the tables, stored procedures, triggers, constraints and all the dependencies in one SQL statement

    Is there any way in which I can clean a database in SQl Server 2005 by dropping all the tables and d ...

  4. JDBC中的Statement和PreparedStatement的区别

    JDBC中的Statement和PreparedStatement的区别  

  5. SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT'OpenRowset/OpenDatasource' 的访问

    delphi ado 跨数据库访问 语句如下 ' and db = '帐套1' 报错内容是:SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATE ...

  6. Exception:HTTP Status 500 - org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

    主要错误信息如下: HTTP Status 500 - org.apache.ibatis.binding.BindingException: Invalid bound statement (not ...

  7. SQL SERVER 2005删除维护作业报错:The DELETE statement conflicted with the REFERENCE constraint "FK_subplan_job_id"

    案例环境: 数据库版本: Microsoft SQL Server 2005 (Microsoft SQL Server 2005 - 9.00.5000.00 (X64) ) 案例介绍: 对一个数据 ...

  8. 第1章 重构,第一个案例(2):分解并重组statement函数

    2. 分解并重组statement (1)提炼switch语句到独立函数(amountFor)和注意事项. ①先找出函数内的局部变量和参数:each和thisAmount,前者在switch语句内未被 ...

  9. 第1章 重构,第一个案例(1):糟糕的statement函数设计

    1. 启航:影片出租,计算每一位顾客的消费金额并打印清单 1.1 场景说明: (1)影片分类规则:普通片.儿童片和新片等3类 (2)每种影片计算租金的方式. ①普通片:基本租金为2元,超过2天的部分每 ...

  10. jdbc执行Statement接口的步骤

    jdbc执行Statement接口的步骤如下: 1)驱动注册程序: Class.forName(com.mysql.jdbc.Driver); 2)获取连接对象: Connection conn = ...

随机推荐

  1. Git客户端搭建环境(Windows系统)的使用

    本文环境: 操作系统:Windows XP SP3 Git客户端:TortoiseGit-1.8.8.0-32bit 一.安装Git客户端 全部安装均采用默认! 1. 安装支撑软件 msysgit:  ...

  2. Idea 使用的技巧和设置

    1.自动提示时候,忽绿大小写, setting---->sensitive 2:IntelliJ IDEA报错class is never used 图中的unused declaration选 ...

  3. pinpoint改造支持查询

    原架构 改造后架构

  4. iOS 动态修改导航栏颜色 UINavigationBar

    示例 所谓动态修改  意思是 在当前页面滚动的过程中 亦或 是在 触发返回事件\进入一个新的页面  导航栏的动态变化 由于系统级别的navBar 高度集成  很多自己想实现的功能 很不好弄 如果是通过 ...

  5. 动态创建selectjs 操作select和option

    1.动态创建select function createSelect(){ var mySelect = document.createElement("select"); myS ...

  6. 【leetcode刷题笔记】Spiral Matrix II

    Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. For ...

  7. python 3 mysql 索引原理与慢查询优化

    python 3 mysql 索引原理与慢查询优化 一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最 ...

  8. 如何在 Eclipse 中使用命令行

    虽然我们已经有了像 Eclipse 这样高级的 IDE,但是我们有时候也是需要在开发的时候使用 Windows 的命令行,来运行一些独立的程序.在两个程序中切换来切换去是很麻烦的.所以 Eclipse ...

  9. debian下为stm32f429i-discovery编译uboot、linux内核和根文件系统

    交叉编译器:arm-uclinuxeabi-2010q1 交叉编译器下载下来后解压,然后将其中bin文件夹路径加入到PATH变量中. 根据<debian下烧写stm32f429I discove ...

  10. LINQ 学习路程 -- 查询操作 Quantifier Operators All Any Contain

    Operator Description All 判断所有的元素是否满足条件 Any 判断存在一个元素满足条件 Contain 判断是否包含元素 IList<Student> studen ...