题目描述

  Alice和Bob正在一棵树上玩游戏。这棵树有\(n\)个结点,编号由\(1\)到\(n\)。他们一共玩\(q\)盘游戏。

  在第\(i\)局游戏中,Alice从结点\(a_i\)出发,Bob从结点\(b_i\)出发。开始时,除了\(a_i\)和\(b_i\)这两个结点外,所有结点都没有染色。结点\(a_i\)被Alice染色,结点\(b_i\)被Bob染色。

  接下来,两位玩家轮流移动,两位玩家移动步数之和为\(k_i\)步。Alice走第一步,Bob走第二步,Alice走第三步\(\cdots\)在每一步中,玩家可以移动到相邻的结点并把该结点染色。注意一个结点可以被多次染色:在任意时刻,每个被染过色的结点的颜色为最后到达过该结点的玩家染的颜色。

  记游戏结束时Alice染色的结点数为\(A\) , Bob染色的结点数为\(B\) 。Alice 想要\((A - B)\)尽量大,Bob 想要\((A - B)\)尽量小。如果两个玩家都以最优策略玩的话,我们想知道最后的\((A - B)\)值是多少。

  \(n,q\leq 20000\)

题解

  设两人之间距离为\(d\)。

  两个人可以相遇或不相遇。

  相遇:

  \(k\)奇\(d\)偶:\(1\)

  \(k\)奇\(d\)奇:\(2\)

  \(k\)偶\(d\)偶:\(-1\)

  \(k\)偶\(d\)奇:\(0\)

  不相遇:

  \(k\)奇:1

  \(k\)偶:0

  如果\(k\)奇,那么对\(Bob\)来说不相遇更优,他就需要逃跑。

  如果\(k\)偶,那么\(Alice\)就要逃跑。

  判断逃跑是否成功就是看这个人在不经过另一个人能到达的点的情况下能走多少步。

  可以发现逃跑路径的终点一定是直径的一个端点。

  可以通过树形DP求出子树内直径和子树外直径。

  时间复杂度:\(O(n+q\log n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector<int> g[200010];
int n,q;
struct node
{
int f,t,w,d,s,ms;
};
node a[200010];
int ti;
int w[200010];
void dfs(int x,int fa,int dep)
{
a[x].f=fa;
a[x].d=dep;
a[x].s=1;
int s=0;
for(vector<int>::iterator p=g[x].begin();p!=g[x].end();p++)
{
int v=*p;
if(v!=fa)
{
dfs(v,x,dep+1);
a[x].s+=a[v].s;
if(a[v].s>s)
{
s=a[v].s;
a[x].ms=v;
}
}
}
}
void dfs2(int x,int top)
{
a[x].t=top;
a[x].w=++ti;
w[ti]=x;
if(a[x].ms)
dfs2(a[x].ms,top);
for(vector<int>::iterator p=g[x].begin();p!=g[x].end();p++)
{
int v=*p;
if(v!=a[x].f&&v!=a[x].ms)
dfs2(v,v);
}
}
int getlca(int x,int y)
{
while(a[x].t!=a[y].t)
if(a[a[x].t].d>a[a[y].t].d)
x=a[a[x].t].f;
else
y=a[a[y].t].f;
return a[x].d<a[y].d?x:y;
}
int jump(int x,int d)
{
while(a[x].w-a[a[x].t].w<d)
{
d-=a[x].w-a[a[x].t].w+1;
x=a[a[x].t].f;
}
return w[a[x].w-d];
}
struct p1{int d,x;p1(int a=0,int b=0):x(a),d(b){}};
int operator <(p1 a,p1 b){return a.d<b.d;}
int operator >(p1 a,p1 b){return a.d>b.d;}
p1 operator +(p1 a,int b){a.d+=b;return a;}
struct p2{int d,x,y;p2(int a=0,int b=0,int c=0):x(a),y(b),d(c){}};
int operator <(p2 a,p2 b){return a.d<b.d;}
int operator >(p2 a,p2 b){return a.d>b.d;}
p2 operator +(p1 a,p1 b){p2 c;c.d=a.d+b.d;c.x=a.x;c.y=b.x;return c;}
p2 operator +(p2 a,int b){a.d+=b;return a;}
p1 f1[200010];
p2 f2[200010];
p1 fir[200010];
p1 sec[200010];
p1 thi[200010];
p2 fir1[200010];
p2 sec1[200010];
p1 g1[200010];
p2 g2[200010];
void dfs3(int x)
{
f1[x]=p1(x,1);
f2[x]=p2(x,x,1);
fir[x].d=sec[x].d=thi[x].d=fir1[x].d=sec1[x].d=-1;
for(vector<int>::iterator p=g[x].begin();p!=g[x].end();p++)
{
int v=*p;
if(v!=a[x].f)
{
dfs3(v);
f2[x]=max(f2[x],f1[x]+f1[v]);
f2[x]=max(f2[x],f2[v]);
f1[x]=max(f1[x],f1[v]+1);
if(f1[v]>fir[x])
{
thi[x]=sec[x];
sec[x]=fir[x];
fir[x]=f1[v];
}
else if(f1[v]>sec[x])
{
thi[x]=sec[x];
sec[x]=f1[v];
}
else if(f1[v]>thi[x])
thi[x]=f1[v];
if(f2[v]>fir1[x])
{
sec1[x]=fir1[x];;
fir1[x]=f2[v];
}
else if(f2[v]>sec1[x])
sec1[x]=f2[v];
}
}
}
void dfs4(int x)
{
for(vector<int>::iterator p=g[x].begin();p!=g[x].end();p++)
{
int v=*p;
if(v!=a[x].f)
{
g1[v]=p1(x,1);
g2[v]=p2(x,x,1);
if(f1[v].x==fir[x].x)
{
g2[v]=max(g2[v],max(max(sec[x]+thi[x],sec[x]+g1[x]),thi[x]+g1[x])+1);
g2[v]=max(g2[v],max(sec[x],g1[x])+p1(x,1));
g1[v]=max(g1[v],max(sec[x],g1[x])+1);
}
else if(f1[v].x==sec[x].x)
{
g2[v]=max(g2[v],max(max(fir[x]+thi[x],fir[x]+g1[x]),thi[x]+g1[x])+1);
g2[v]=max(g2[v],max(fir[x],g1[x])+p1(x,1));
g1[v]=max(g1[v],max(fir[x],g1[x])+1);
}
else
{
g2[v]=max(g2[v],max(max(fir[x]+sec[x],fir[x]+g1[x]),sec[x]+g1[x])+1);
g2[v]=max(g2[v],max(fir[x],g1[x])+p1(x,1));
g1[v]=max(g1[v],max(fir[x],g1[x])+1);
}
if(f2[v].x==fir1[x].x)
g2[v]=max(g2[v],max(sec1[x],g2[x]));
else
g2[v]=max(g2[v],max(fir1[x],g2[x]));
dfs4(v);
}
}
}
int getdist(int x,int y)
{
return a[x].d+a[y].d-2*a[getlca(x,y)].d;
}
int gao(int x,int y,int lca,int d)
{
int dist=a[x].d+a[y].d-2*a[lca].d;
if(dist<=d)
return -1;
if(d>=a[x].d-a[lca].d)
{
int z=jump(y,dist-d-1);
int x1=f2[z].x;
int x2=f2[z].y;
return max(getdist(y,x1),getdist(y,x2));
}
else
{
int z=jump(x,d);
int x1=g2[z].x;
int x2=g2[z].y;
return max(getdist(y,x1),getdist(y,x2));
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
#endif
scanf("%d%d",&n,&q);
int i,x,y;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,0,1);
dfs2(1,1);
dfs3(1);
g1[1]=p1(1,-1);
g2[1]=p2(1,1,-1);
dfs4(1);
int k;
for(i=1;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&k);
int lca=getlca(x,y);
int d=a[x].d+a[y].d-2*a[lca].d;
if(k&1)
{
if(gao(x,y,lca,(k+1)/2)>=k/2)
printf("1\n");
else if(d&1)
printf("2\n");
else
printf("1\n");
}
else
{
if(gao(y,x,lca,k/2)>=(k+1)/2)
printf("0\n");
else if(d&1)
printf("0\n");
else
printf("-1\n");
}
}
return 0;
}

【XSY2190】Alice and Bob VI 树形DP 树剖的更多相关文章

  1. BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca

    BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...

  2. 【HDU 5233】Tree chain problem (树形DP+树剖+线段树|树状数组)最大权不相交树链集

    [题目] Tree chain problem Problem Description Coco has a tree, whose vertices are conveniently labeled ...

  3. 树形DP+树状数组 HDU 5877 Weak Pair

    //树形DP+树状数组 HDU 5877 Weak Pair // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 // 这道题要离散化 #i ...

  4. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  5. POJ 3162.Walking Race 树形dp 树的直径

    Walking Race Time Limit: 10000MS   Memory Limit: 131072K Total Submissions: 4123   Accepted: 1029 Ca ...

  6. HDU 2196.Computer 树形dp 树的直径

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  7. POJ 1655.Balancing Act 树形dp 树的重心

    Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14550   Accepted: 6173 De ...

  8. hdu 4607 树形dp 树的直径

    题目大意:给你n个点,n-1条边,将图连成一棵生成树,问你从任意点为起点,走k(k<=n)个点,至少需要走多少距离(每条边的距离是1): 思路:树形dp求树的直径r: a:若k<=r+1 ...

  9. computer(树形dp || 树的直径)

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

随机推荐

  1. flask实现子域名

    什么是子域名? 子域名,类似于xxx.douban.com的形式,如book.douban.com,music.douban.com,movie.douban.com等 用flask怎么实现子域名? ...

  2. Centos7 下SVN迁移

    SVN迁移需要做如下操作: 1. 将原来的Repository导出 . #svnadmin dump 原有repos的目录路径 > dumpfile (不同服务器安装目录不同,根据具体情况调整) ...

  3. H5 57-文章界面

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. matplotlib 入门之Image tutorial

    文章目录 载入图像为ndarray 显示图像 调取各个维度 利用cmp 获得像素点的RGB的统计 通过clim来限定rgb 标度在下方 插值,马赛克,虚化 matplotlib教程学习笔记 impor ...

  5. 使用 Markdown编辑

    作用: 学习笔记,整理日志, 发布日记,杂文,所见所想 撰写发布技术文稿(代码支持) 撰写发布学术论文(LaTeX 公式支持) sublime text3插件 输入 Shift + Ctrl + P, ...

  6. Java Core - Map接口

    Map:是一组映射The java.util.Map interface represents a mapping between a key and a value. The Map interfa ...

  7. JMeter中返回Json数据的处理方法(转)

    Json 作为一种数据交换格式在网络开发,特别是 Ajax 与 Restful 架构中应用的越来越广泛.而 Apache 的 JMeter 也是较受欢迎的压力测试工具之一,但是它本身没有提供对于 Js ...

  8. Ajax发送请求等待时弹出模态框等待提示

    主要的代码分为两块,一个是CSS定义模态框,另一个是在Ajax中弹出模态框. 查看菜鸟教程中的模态框教程demo,http://www.runoob.com/try/try.php?filename= ...

  9. mysql数据库修改数据表引擎的方法

    对于MySQL数据库,如果你要使用事务以及行级锁就必须使用INNODB引擎.如果你要使用全文索引,那必须使用myisam. INNODB的实用性,安全性,稳定性更高但是效率比MYISAM稍差,但是有的 ...

  10. python之路--网络通信协议

    一 . osi七层协议 互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层 二 . tcp三次握手和四次挥手 我们知道网络层,可以实现两个主机之间的通信.但是这并不具体,因为,真 ...