题目描述

  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. H5 70-清除浮动方式五

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

  2. 实时采集新加坡交易所A50指数

    http://www.investing.com/indices/ftse-china-a50 前段时间有人问我如何得到这个网页的实时指数变化,经过抓包发现该网站提供的指数实时变化是通过Websock ...

  3. kubectl常用命令汇总

    #查看k8s的所有node节点 kubectl get node #查看ns的pod kubectl get pod --all-namespaces -o wide kubectl get pod ...

  4. XT535

    今天金山误删了一个文件,把手机系统整坏了,故刷了个机,刷机教程: http://bbs.dospy.com/thread-15027415-1-623-1.html 中间安装了个驱动精灵,否则手机开启 ...

  5. Golang中进行reslice时的注意事项

    先看下面代码: package main import "fmt" func main() { slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8} ...

  6. nginx强制使用https访问(http跳转到https)

    Nginx 的 Location 从零开始配置 - 市民 - SegmentFault 思否https://segmentfault.com/a/1190000009651161 nginx配置loc ...

  7. Laravel Providers——服务提供者的注册与启动源码解析

      本文 GitBook 地址: https://www.gitbook.com/book/leoyang90/laravel-source-analysishttps://learnku.com/a ...

  8. Windows 激活的简单办法(能上网)

    1. 之前很多机器上面总是提示我  盗版系统看起来挺不high的 2. 还是使用之前的办法来进行激活 slmgr  (之前写过) /ipk <Product Key> 安装产品密钥(替换现 ...

  9. 下拉框插件select2的使用

    它的优点有: 样式还算好看,支持多选,支持索搜 下面来介绍下select2的用法 1.最简单的用法 只需要加载css和js即可使用 <select name="" id=&q ...

  10. js的日期操作:String转date日期格式、求日期差

    一.在js中String类型转成date格式 var date = new Date("2018-9-21 14:58:43");//就是这么简单 二.date转String类型就 ...