## 题目描述

给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白

有两种操作:

0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑)

1 v : 询问1到v的路径上的第一个黑点,若无,输出-1

输入输出格式

输入格式:

第一行 N,Q,表示N个点和Q个操作

第二行到第N行N-1条无向边

再之后Q行,每行一个操作"0 i" 或者"1 v" (1 ≤ i, v ≤ N).

输出格式:

对每个1 v操作输出结果

输入输出样例

输入样例#1: 复制

9 8

1 2

1 3

2 4

2 9

5 9

7 9

8 9

6 8

1 3

0 8

1 6

1 7

0 2

1 9

0 2

1 9

输出样例#1: 复制

-1

8

-1

2

-1

说明

For 1/3 of the test cases, N=5000, Q=400000.

For 1/3 of the test cases, N=10000, Q=300000.

For 1/3 of the test cases, N=100000, Q=100000.

Solution

这题显然是树链剖分,先把dfs序处理出来,但线段树存什么呢?可以发现,若以1为根,进行dfs序,这样1到每个点之间的最早出现的黑点,显然是dfs序最小值,这样线段树存最小值就行了,我们还要把线段树上的点映射回树中结点。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll(x) (x*2)
#define rr(x) (x*2+1)
using namespace std;
struct Node
{
int to,next;
}a[201001];
int len,last[200110],siz[201010],son[201100],dep[201001],fa[200010],yuan[200101];
int id[201010],cnt,n,sum[400101],top[400101],mn[400110];
void add(int a1,int a2)
{
a[++len].to=a2;
a[len].next=last[a1];
last[a1]=len;
}
void dfs1(int x,int father)
{
int mxson=-1;siz[x]=1;
for(int i=last[x];i;i=a[i].next)
{
int to=a[i].to;
if(to==father) continue;
dep[to]=dep[x]+1;
fa[to]=x;
dfs1(to,x);
siz[x]+=siz[to];
if(siz[to]>mxson) son[x]=to,mxson=siz[to];
}
}
void dfs2(int x,int topf)
{
id[x]=++cnt;
yuan[cnt]=x;
top[x]=topf;
if(!son[x]) return;
dfs2(son[x],topf);
for(int i=last[x];i;i=a[i].next)
{
int to=a[i].to;
if(to==fa[x]||to==son[x]) continue;
dfs2(to,to);
}
}
void pushup(int node){mn[node]=min(mn[ll(node)],mn[rr(node)]);}
void gai(int node,int l,int r,int pos)
{
if(l==r) {sum[node]^=1;if(sum[node]==1) mn[node]=l;else mn[node]=1e9;return;}
int mid=(l+r)/2;
if(pos<=mid) gai(ll(node),l,mid,pos);
else gai(rr(node),mid+1,r,pos);
pushup(node);
}
int cha(int node,int l,int r,int left,int right)
{
if(l>=left&&r<=right) return mn[node];
int mid=(l+r)/2,ans=1e9;
if(left<=mid) ans=min(ans,cha(ll(node),l,mid,left,right));
if(right>mid) ans=min(ans,cha(rr(node),mid+1,r,left,right));
return ans;
}
int cha1(int x,int y)
{
int ans=1e9;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans=min(ans,cha(1,1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans=min(ans,cha(1,1,n,id[x],id[y]));
if(ans==1e9)
return -1;
return yuan[ans];
}
int main()
{
for(int i=0;i<=400000;i++)
mn[i]=1e9;
int q,x,y,opt;
cin>>n>>q;
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
dep[1]=1;
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&opt,&x);
if(opt==0)
gai(1,1,n,id[x]);
else
printf("%d\n",cha1(1,x));
}
}

博主蒟蒻,可以随意转载,但必须附上原文链接k-z-j

Qtree3的更多相关文章

  1. [题解]luogu P4116 Qtree3

    终于来到了Qtree3, 其实这是Qtree系列中最简单的一道题,并不需要线段树, 只要树链剖分的一点思想就吼了. 对于树链剖分剖出来的每一根重链,在重链上维护一个Set就好了, 每一个Set里存的都 ...

  2. SPOJ QTREE3 Query on a tree again! ——Link-Cut Tree

    [题目分析] QTREE2,一看是倍增算法,太懒了,不写了.( ̄_, ̄ ) QTREE3,树链剖分可以做,发现链上的问题LCT也很好做. 要是子树问题貌似可以DFS序. 然后就成LCT模板题了. 考前 ...

  3. 树链剖分&咕咕咕了好久好久的qtree3

    前言 显然qtree系列都是树链剖分辣 发现自己没有专门整理过树链剖分耶 辣么就把这篇博客魔改成树链剖分好辣(貌似除了树剖也没什么好写的) 正文 废话了辣么多终于开始了 一.树剖怎么写鸭 二.树剖有什 ...

  4. QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树

    Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...

  5. Qtree3题解(树链剖分(伪)+线段树+set)

    外话:最近洛谷加了好多好题啊...原题入口 这题好像是SPOJ的题,挺不错的.看没有题解还是来一篇... 题意: 很明显吧.. 题解: 我的做法十分的暴力:树链剖分(伪)+线段树+\(set\)... ...

  6. P4116 Qtree3

    思路 可以树剖可以LCT,树剖就是每个重链开一个SET维护一下黑点的深度 非常不优美 使用LCT,在splay上二分找出需要的节点即可 代码 #include <cstdio> #incl ...

  7. Qtree3题解(树链剖分+线段树+set)

    外话:最近洛谷加了好多好题啊...原题入口 这题好像是SPOJ的题,挺不错的.看没有题解还是来一篇... 题意 很易懂吧.. 题解 我的做法十分的暴力:树链剖分(伪)+线段树+ std :: set ...

  8. 洛谷 P4116 Qtree3

    Qtree系列第三题 我是题面 读完题大概不难判断是一道树剖的题 这道题的关键是记录两种状态,以及黑点的序号(不是编号) 线段树啊当然 定义两个变量v,f,v表示距离根节点最近的黑点,默认-1,f则表 ...

  9. 【洛谷 P4116】 Qtree3 (树链剖分)

    题目链接 树剖练手题,想复习下树剖. 第一次提交\(T\)成QQC 看我 ??? 看了数据范围的确挺恶心的,我的复杂度是\(O(Mlog^2N)\)的,数据范围有三段 For 1/3 of the t ...

  10. 树链剖分【p4116】Qtree3 - Query on a tree

    Description 给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白 有两种操作: 0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑) 1 v : 询问1到v的路径上的第一个黑 ...

随机推荐

  1. Linux用户空间与内核空间(理解高端内存)【转】

    转自:http://www.cnblogs.com/wuchanming/p/4360277.html Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递 ...

  2. Scrapy学习-11-Selector对象使用

    Selector使用 使用背景 我需要使用类似spider项目中,response使用的xpath和css获取页面指定数据,但因为爬取页面较小我们不想创建一个spider项目时,就可以使用scrapy ...

  3. HYSBZ 1026: windy数(数位DP)

    类型:数位DP题意:不含前导零且相邻两个数字之差至少为2的正整数被称为windy数.问[A,B]之间windy数的个数.(1 <= A <= B <= 2000000000 ) 思路 ...

  4. 容器中元素的去重——ans.erase(unique(ans.begin(),ans.end()),ans.end());

    啊,原来unique()函数,只是处理的连续的元素,比如 -1 -1 -1 1 2 -1 2 就处理成了 -1 1 2 -1 2 -1 -1并且返回5,之后eraser(5,7)剩下了 -1 1 2 ...

  5. LeetCode OJ--Best Time to Buy and Sell Stock II

    http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ 第二问,是说可以进行无数次买卖. 贪心法 #include &l ...

  6. 在js中为对象添加和删除属性

    对于一个普通的js对象: var obj = { name:"mary", age:21 } 如果我们要对它添加新属性的话可以使用下列方式: obj.address = " ...

  7. [Bzoj5358][Lydsy1805月赛]口算训练(预处理+动态开点线段树)

    5358: [Lydsy1805月赛]口算训练 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 318  Solved: 105[Submit][Stat ...

  8. Spring Cloud Eureka 自我保护机制实战分析

    前些天栈长在Java技术栈微信公众号分享过 Spring Cloud Eureka 的系列文章: Spring Cloud Eureka 自我保护机制 Spring Cloud Eureka 常用配置 ...

  9. spring事物,在service层如果进行了异常处理,则不会回滚

    今天进行了事物处理的验证,发现如果在在service层如果进行了异常处理,则不会回滚. 看来异常的处理还是统一放在controller层比较好,service如果是查询方法,出现了异常,就不要做处理了 ...

  10. 邁向IT專家成功之路的三十則鐵律 鐵律十三:IT人理財之道-知足

    身為一位專業的IT人士,工作上不僅要做到滿足興趣與專業熱忱,當然也要做到能夠滿足荷包.現代人賺錢不是問題,但花錢卻出了很大問題,親愛的IT朋友們,請不要將您辛苦賺來的錢花在想要的東西上,實際上需要的卻 ...