2017 ACM/ICPC Asia Regional Shenyang Online Ping Ping Ping 树链剖分+树状数组
来源:互联网 发布:英语课文朗读软件 编辑:程序博客网 时间:2024/05/22 07:08
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6203
题目大意:给出n+1个节点的树( 3<n<10^4),并给出m对点(m<=50000),要求这m对点的最短链上至少有一个点背标记,问最少标记几个点。
先让我哭一会QAQ,昨天下午后半场一直在死磕这题,想了网络流,费用流,差分约束,树形DP就是没想到贪心,最后随便写了一发后效性明显地树形DP,假装没有划水(我好菜。。。。
其实这题可以稍微简化一下,假设只有一条链的情形。就是给出一条链和m对起始点和终点,要求这m对点之间至少有一个点被标记。
从左端点最接近左边界的一对点开始考虑,显然这对点一定要被选中,其次如果直接选中右端点,就可以同时标记最多的链。于是就有了一个贪心算法,每次选中左端点最靠左边界的未被标记的点对,标记这对点中的右端点。
然后回到这道题。对于被标记的点,都肯定有一个性质:是某个点对的LCA。这个可以反证法证明,如果有一个被标记点不是任意一对点的LCA,则不标记这个点,换做标记这个点往根节点遇到的第一个LCA点显然不会使得某个链的标记消失。
接着,对于深度最大的一个LCA,这个LCA肯定是要被标记的,因为不存在其他LCA在这个点对的链路上,于是就有了一个贪心算法,每次标记深度最大的,且其所在链路未被标记的LCA。
怎么知道某一条链路是否被标记过呢?这就很好处理了,只要用树链剖分来处理某个点是否被标记,同时用树状数组查询前缀和,可以得知一段区间内是否有被标记过的点。
代码:
#include <bits/stdc++.h>using namespace std;inline void read(int &x){ char ch; bool flag=false; for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true; for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); x=flag?-x:x;}inline void read(long long &x){ char ch; bool flag=false; for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true; for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); x=flag?-x:x;}inline void write(int x){ static const int maxlen=100; static char s[maxlen]; if (x<0) { putchar('-'); x=-x;} if(!x){ putchar('0'); return; } int len=0; for(;x;x/=10) s[len++]=x % 10+'0'; for(int i=len-1;i>=0;--i) putchar(s[i]);}int const MAXN=11000;int const MAXM=21000;int const MAXQ=61000;int n,m;int pre[ MAXM ] , now[ MAXN ] ,son[ MAXM ],tot;int pos[ MAXN ],cnt;int taken[ MAXN ];int siz[ MAXN ] , deep[ MAXN ];int top[ MAXN ] , fa[ MAXN ];void build(int a,int b){pre[++tot]=now[a];now[a]=tot;son[tot]=b;}void get_size_deep_fa(int x){siz[ x ] = 1;for (int p=now[x];p;p=pre[p]) if( son[p] != fa[ x ] ) { deep[ son[p] ] = deep[ x ] + 1; fa[ son[p] ] = x; get_size_deep_fa( son[p] ); siz[ x ] += siz[ son[p] ]; }}void get_pos_top(int x,int fa){bool op=0;int Max = 0;int Maxi = 0 ;++cnt; pos[ x ] = cnt;for (int p = now[ x ] ; p ; p=pre[p] ) if ( son[p] != fa ) if ( Max < siz[ son[p] ] ) { Max = siz[ son[p] ]; Maxi = son[p] ; }if ( Maxi ) { top[ Maxi ] = top[ x ]; get_pos_top( Maxi , x ); }for (int p = now[ x ]; p ; p=pre[p] ) if ( ( son[p]!=fa) && ( son[p]!=Maxi ) ) { top[ son[p] ] = son[p]; get_pos_top( son[p] , x ); }}int lowbit( int x){return x&(-x);}int get_taken(int x ){int sum=0;while( x ) { sum+=taken[ x ]; x-=lowbit( x ); }return sum;}void add(int x){while ( x<=n ) { taken[ x ]++; x+=lowbit( x ); }}struct Query{ int u , v ,lca; void get_lca(){ int x = u , y= v; while ( top[ x ] != top[ y ] ) { if ( deep [ top[ x ] ] > deep [ top[ y ] ]) swap ( x , y ); y = fa [ top[ y ] ]; } lca = ( deep [ x ] < deep [ y ] )?x:y; } bool exist(){ int x = u , y= v; while ( top[ x ] != top[ y ] ) { if ( deep [ top[ x ] ] > deep [ top[ y ] ]) swap ( x , y ); if ( get_taken( pos[ y ] ) - get_taken( pos[ top[ y ] ]-1 ) != 0 ) return 0; y = fa [ top[ y ] ]; } if ( get_taken( pos[ x ] ) - get_taken( pos[ lca ]-1 ) !=0) return 0; if ( get_taken( pos[ y ] ) - get_taken( pos[ lca ]-1 ) !=0) return 0; return 1; }}que[ MAXQ ];bool cmp(Query A , Query B){return deep[ A.lca ] > deep[ B.lca ];}int main(){ while (scanf("%d",&n)!=EOF) { tot=0; memset(now,0,sizeof(now)); n++; for (int i=1;i<n;i++) { int a,b; read(a); read(b); a++; b++; build( a , b ); build( b , a ); } cnt=0; deep[1]=0; fa[1]=0; get_size_deep_fa( 1 ); top[1]=1; get_pos_top( 1 , 0 ); read(m); for (int i=1;i<=m;i++) { read( que[i].u ); read( que[i].v ); que[i].u++; que[i].v++; que[i].get_lca(); } sort( que+1 , que+m+1 , cmp ); memset( taken , 0 , sizeof( taken ) ); for (int i=1;i<=m;i++) if (que[i].exist()) add( pos [ que[i].lca ] ); printf("%d\n",get_taken( n ) ); } return 0;}
阅读全文
0 0
- 2017 ACM/ICPC Asia Regional Shenyang Online Ping Ping Ping 树链剖分+树状数组
- HDU 6203 ping ping ping (LCA + 树状数组, 2017 ACM/ICPC Asia Regional Shenyang Online)
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional Shenyang Online
- 2017 ACM/ICPC Asia Regional shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2015 ACM/ICPC Asia Regional Shenyang Online
- 2016 ACM/ICPC Asia Regional Shenyang Online
- Problem 1002-2017 ACM/ICPC Asia Regional Shenyang Online
- Problem 1004-2017 ACM/ICPC Asia Regional Shenyang Online
- 关于编译debug和release的方式
- 软件设计原则
- 操作系统-内存管理-内存空间的连续分配方式
- python中is和==
- java序列化
- 2017 ACM/ICPC Asia Regional Shenyang Online Ping Ping Ping 树链剖分+树状数组
- Linux下jdk的安装以及配置
- C# checked和unchecked详解
- 资讯精选 | 开发一套高可用的物联网设备分几步? zGlue:放着我来
- vue-router 学习笔记
- 设置网站ico图标的两种方法
- Java 内存模型及GC原理
- 无需第三方软件实现Mac支持ntfs读写的最简单操作
- ReactNative中SectionList实现条目GridView效果