bzoj 3637: Query on a tree VI 树链剖分 && AC600
3637: Query on a tree VI
Time Limit: 8 Sec Memory Limit: 1024 MB
Submit: 206 Solved: 38
[Submit][Status][Discuss]
Description
You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 to n.
Each node has a color, white or black. All the nodes are black initially.
We will ask you to perfrom some instructions of the following form:
- 0 u : ask for how many nodes are connected to u, two nodes are connected iff all the node on the path from u to v (inclusive u and v) have a same color.
- 1 u : toggle the color of u(that is, from black to white, or from white to black).
Input
The first line contains a number n denoted how many nodes in the tree(1 ≤ n ≤ 105). The next n - 1 lines, each line has two numbers (u, v) describe a edge of the tree(1 ≤ u, v ≤ n). The next line contains a number m denoted how many operations we are going to process(1 ≤ m ≤ 105). The next m lines, each line describe a operation (t, u) as we mentioned above(0 ≤ t ≤ 1, 1 ≤ u ≤ n).
Output
For each query operation, output the corresponding result.
Sample Input
1 2
1 3
1 4
1 5
3
0 1
1 1
0 1
Sample Output
1
HINT
Source
这道题常数卡的有点紧,我树链剖分用一棵线段树存就TLE了,每个链分别建线段树才行。
考虑将每一个同色块的答案保存在这一块深度最浅的那一个点(这是一个很好的思路),我们考虑如何维护即可,对于每一个点,我们维护f[now][0/1]表示当前点如果取白色/黑色,所在的子树中与这个点同色的联通块大小。
每次颜色修改只会影响到当前点到根节点路径上的一段。而且还是路径加减一个数,这可以用链剖维护。
询问时只用跳到当前联通块最上方的点,然后输出该点所存的f值即可。
AC600了,lalala~~
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 101000
#define MAXV MAXN*2
#define MAXE MAXV*2
#define MAXT MAXN*4
#define lch sgt[now].lc
#define rch sgt[now].rc
#define smid ((l+r)>>1)
#define INF 0x3f3f3f3f
struct Edge
{
int np;
Edge *next;
}E[MAXE],*V[MAXV];
int tope=-;
void addedge(int x,int y)
{
E[++tope].np=y;
E[tope].next=V[x];
V[x]=&E[tope];
} int q[MAXN];
int pnt[MAXN];
int siz[MAXN];
int son[MAXN],top[MAXN],pos[MAXN],apos[MAXN],dfstime;
void bfs(int now)
{
int head=-,tail=;
Edge *ne;
q[]=now;
pnt[now]=;
while (head<tail)
{
now=q[++head];
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now])continue;
pnt[ne->np]=now;
q[++tail]=ne->np;
}
}
for (int i=tail;i>=;i--)
{
now=q[i];
siz[now]=;
int mxsiz=;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now])continue;
siz[now]+=siz[ne->np];
if (siz[ne->np]>mxsiz)
{
mxsiz=now;
son[now]=ne->np;
}
}
}
}
int stack[MAXN],tops=-;
void dfs(int now)
{
Edge *ne;
stack[++tops]=now;
top[now]=now;
while (~tops)
{
now=stack[tops--];
pos[now]=++dfstime;
apos[dfstime]=now;
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==pnt[now] || ne->np==son[now])continue;
stack[++tops]=ne->np;
top[ne->np]=ne->np;
}
if (son[now])
{
stack[++tops]=son[now];
top[son[now]]=top[now];
}
}
}
int col[MAXN];
int ptra[MAXN];
struct sgt_node
{
int lc,rc;
int sum[];
int pls[];
int val[];
}sgt[MAXT];
int topt=;
void make_plus(int now,int c,int d)
{
sgt[now].val[c]+=d;
sgt[now].pls[c]+=d;
}
void down(int now)
{
if (sgt[now].pls[])
{
make_plus(lch,,sgt[now].pls[]);
make_plus(rch,,sgt[now].pls[]);
sgt[now].pls[]=;
}
if (sgt[now].pls[])
{
make_plus(lch,,sgt[now].pls[]);
make_plus(rch,,sgt[now].pls[]);
sgt[now].pls[]=;
}
}
int Build_sgt(int l,int r)
{
int now=++topt;
sgt[now].val[]=sgt[now].val[]=sgt[now].pls[]=sgt[now].pls[]=;
sgt[now].sum[]=;
sgt[now].sum[]=;
if (l==r)
{
ptra[l]=now;
sgt[now].val[]=siz[apos[l]];
sgt[now].val[]=;
return now;
}
lch=Build_sgt(l,smid);
rch=Build_sgt(smid+,r);
return now;
}
pair<int,int> Query_sgt(int now,int l,int r,int pos)
{
if (l==r)
return make_pair(sgt[now].val[],sgt[now].val[]);
down(now);
if (pos<=smid)
return Query_sgt(lch,l,smid,pos);
else
return Query_sgt(rch,smid+,r,pos);
}
void Modify_sgt(int now,int l,int r,int x,int y,int c,int d)
{
if (l==x && r==y)
{
make_plus(now,c,d);
return ;
}
down(now);
if (y<=smid)
return Modify_sgt(lch,l,smid,x,y,c,d);
else if (smid<x)
return Modify_sgt(rch,smid+,r,x,y,c,d);
else
{
Modify_sgt(rch,smid+,r,smid+,y,c,d);
Modify_sgt(lch,l,smid,x,smid,c,d);
}
}
void Modify_sgt2(int now,int l,int r,int pos)
{
if (l==r)
return swap(sgt[now].sum[],sgt[now].sum[]);
down(now);
if (pos<=smid)
Modify_sgt2(lch,l,smid,pos);
else
Modify_sgt2(rch,smid+,r,pos);
sgt[now].sum[]=sgt[lch].sum[]+sgt[rch].sum[];
sgt[now].sum[]=sgt[lch].sum[]+sgt[rch].sum[];
}
int Scan_sgt(int now,int l,int r,int x,int y,int c)
{
if (l==x && r==y)
{
if (sgt[now].sum[c]==(r-l+))
{
return l;
}else if (sgt[now].sum[c]==)
{
return -;
}else
{
down(now);
int ret=Scan_sgt(rch,smid+,r,smid+,y,c);
if (ret==smid+)
{
ret=Scan_sgt(lch,l,smid,x,smid,c);
if (ret==-)return smid+;
else return ret;
}else return ret;
}
}
down(now);
if (y<=smid)
return Scan_sgt(lch,l,smid,x,y,c);
else if (smid<x)
return Scan_sgt(rch,smid+,r,x,y,c);
else
{
int ret=Scan_sgt(rch,smid+,r,smid+,y,c);
if (ret==smid+)
{
ret=Scan_sgt(lch,l,smid,x,smid,c);
if (ret==-)return smid+;
else return ret;
}else return ret;
}
}
int spos[MAXN],tpos[MAXN];
int troot[MAXN];
int Swim_up(int x)
{
int rpos=pos[x];
int c=col[x];
while (x)
{
int y=Scan_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x],c);
if (y==-)break;
else if (y!=pos[top[x]])
{
rpos=y;break;
}else
{
rpos=y;
x=pnt[top[x]];
}
}
return apos[rpos];
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
int n,m;
int x,y,z;
scanf("%d",&n);
for (int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
bfs();
dfs();
for (int i=;i<=n;i++)
spos[i]=INF,tpos[i]=-INF;
for (int i=;i<=n;i++)
spos[top[i]]=min(spos[top[i]],pos[i]);
for (int i=;i<=n;i++)
tpos[top[i]]=max(tpos[top[i]],pos[i]);
for (int i=;i<=n;i++)
if (top[i]==i)
troot[i]=Build_sgt(spos[i],tpos[i]);
scanf("%d",&m);
int opt;
for (int i=;i<=n;i++)col[i]=;
for (int i=;i<m;i++)
{
scanf("%d%d",&opt,&x);
if (opt==)
{
int rpt=Swim_up(x);
pair<int,int> res=Query_sgt(troot[top[rpt]],spos[top[rpt]],tpos[top[rpt]],pos[rpt]);
if (col[x]==)
printf("%d\n",res.first);
else
printf("%d\n",res.second);
}else
{
pair<int,int> res=Query_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x]);
int p=pnt[x];
int c=col[p];
int d,d2;
if (col[p]== && col[x]==)d=-res.second,d2=res.first;
else if (col[p]== && col[x]==)d=res.second,d2=-res.first;
else if (col[p]== && col[x]==)d=res.first,d2=-res.second;
else d=-res.first,d2=res.second;
if (p)
{
sgt[ptra[pos[p]]].val[c^]+=d2;
int a=Swim_up(p);
a=pnt[a];
if (!a)a=;
while (true)
{
if (top[p]==top[a])
{
Modify_sgt(troot[top[a]],spos[top[a]],tpos[top[a]],pos[a],pos[p],c,d);
break;
}
Modify_sgt(troot[top[p]],spos[top[p]],tpos[top[p]],pos[top[p]],pos[p],c,d);
p=pnt[top[p]];
}
}
Modify_sgt2(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x]);
col[x]^=;
}
}
}
bzoj 3637: Query on a tree VI 树链剖分 && AC600的更多相关文章
- SPOJ QTREE6 Query on a tree VI 树链剖分
题意: 给出一棵含有\(n(1 \leq n \leq 10^5)\)个节点的树,每个顶点只有两种颜色:黑色和白色. 一开始所有的点都是黑色,下面有两种共\(m(1 \leq n \leq 10^5) ...
- [BZOJ 3637]Query on a tree VI
偶然看见了这题,觉得自己 QTREE.COT 什么的都没有刷过的真是弱爆了…… 一道思路很巧妙的题,终于是在约大爷的耐心教导下会了,真是太感谢约大爷了. 这题显然是树链剖分,但是链上维护的东西很恶心. ...
- QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树
Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...
- spoj 375 Query on a tree(树链剖分,线段树)
Query on a tree Time Limit: 851MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Sub ...
- SPOJ 375 Query on a tree(树链剖分)(QTREE)
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- SPOJ QTREE - Query on a tree 【树链剖分模板】
题目链接 引用到的大佬博客 代码来自:http://blog.csdn.net/jinglinxiao/article/details/72940746 具体算法讲解来自:http://blog.si ...
- [SPOJ375]QTREE - Query on a tree【树链剖分】
题目描述 给你一棵树,两种操作. 修改边权,查找边权的最大值. 分析 我们都知道,树链剖分能够维护点权. 而且每一条边只有一个,且唯一对应一个儿子节点,那么就把信息放到这个儿子节点上. 注意,lca的 ...
- SPOJ 375 Query on a tree(树链剖分)
https://vjudge.net/problem/SPOJ-QTREE 题意: 给出一棵树,树上的每一条边都有权值,现在有查询和更改操作,如果是查询,则要输出u和v之间的最大权值. 思路: 树链剖 ...
- 【SPOJ Query on a tree 】 (树链剖分)
http://acm.hust.edu.cn/vjudge/problem/13013 题意: 有一棵N个节点的树(1<=N<=10000),N-1条边,边的编号为1~N-1,每条边有一个 ...
随机推荐
- Newtonsoft.Json.dll序列化为json,null值自动过滤
var jSetting = new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}; var json = ...
- 导出Private API
首先介绍下private API 它共分为两类: 1 在官方文档中没有呈现的API(在frameworks 下隐藏) 2 苹果明确申明不能使用的API ,在privateFrameworks 下 然后 ...
- response小结(二)——文件下载
我们先来看一个最简单的文件下载的例子: package com.yyz.response; import java.io.FileInputStream; import java.io.IOExcep ...
- Microsoft Dynamics CRM 2011的组织服务中的RetrieveMultiple方法(转)
本篇文章,介绍Microsoft Dynamics CRM 2011的组织服务中的RetrieveMultiple方法. RetreiveMultiple方法,用于获取实体的多个实例,该方法的签名如下 ...
- button上加上图片的两种方式
//// ViewController.m// UIButtonDemo//// Created by hehe on 15/9/15.// Copyright (c) 2015年 wang. ...
- Php 数据类型
数据类型 JS中二大类 基本数据类型 number string boolean undefined null 复合数据类型 array object function php数据类型分为三大类 标量 ...
- 写在十年 2007-09-15 (写给L之三)
你知道吗? 那种时间很远,但心很近的感觉. 时间已经远去了十年, 但亲切的感觉依然清晰可见, 无论时光远去了十年,二十年,三十年, 永远…… 它已经植根,在心间……
- 仿《雷霆战机》飞行射击手游开发--GameObject
转载请注明:http://www.cnblogs.com/thorqq/p/5646509.html 在上一篇中,我们介绍了各种游戏对象的功能及类的集成关系,现在我们来看看GameObject的源代码 ...
- 用一天的时间学习Java EE中的SSH框架
首先说明一下,本人目前主要从事.NET领域的工作,但对于C++.Java.OC等语言也略知一二,周末闲来无事,特花费一天的时间学习了一下Java中的SSH框架,希望把学习过程中的心得体会与园友们进行分 ...
- 【转】Android SDK Manager 更新方法
在Android SDK Manager Setting 窗口设置HTTP Proxy server和HTTP Proxy Port这个2个参数,分别设置为: HTTP Proxy server:mi ...