[COJ2201][KOJ0223][KOJ0250]花园

试题描述

小奇的花园有n个温室,标号为1到n,温室以及以及温室间的双向道路形成一棵树。

每个温室都种植着一种花,随着季节的变换,温室里的花的种类也在不断发生着变化。

小奇想知道从温室x走到温室y的路径中(包括两个端点),第t种花出现的次数。

输入

第一行为两个整数n,q,表示温室的数目和操作的数目。

第二行有n个整数T1,T2…Tn其中Ti表示温室i中的花的种类。

接下来n-1行,每个两个整数x, y,表示温室x和y之间有一条双向道路。

接下来q行,表示q个操作,分别为以下两种形式之一:

• C x t 表示在温室x中的花的种类变为t。

• Q x y t 表示询问温室x走到温室y的路径中(包括两个端点),第t种花出现的次数。

为了体现在线操作,输入数据中的每个操作的参数都进行了加密。记最后一次询问的答案为anslast(一开始设anslast为0),下次读入中的x,y,t均需要异或上anslast以得到真实值,在C/C++中异或为ˆ运算符,在pascal中为xor运算符。

输出

输出q行,每行一个正整数表示该次询问答案。

输入示例


Q
C
Q
C
Q
C
Q
Q

输出示例


数据规模及约定

对于30%的数据,有n <= 1000, q <= 2000。

对于50%的数据,有n <= 10000, q <= 20000。

对于100%的数据,有n <= 100000, q <= 200000,0 <= T < 2^31。

题解

解法一:树链剖分套线段树套 treap。T 飞~~

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 100010
#define maxm 200010
#define maxnode 7600010 struct Node {
int v, r, siz;
Node() {}
Node(int _, int __): v(_), r(__) {}
} ns[maxnode];
int ToT, fa[maxnode], ch[2][maxnode], rec;
int getnode() {
if(rec) {
int tmp = rec; rec = 0;
fa[tmp] = ch[0][tmp] = ch[1][tmp] = 0;
return tmp;
}
return ++ToT;
}
void maintain(int o) {
if(!o) return ;
ns[o].siz = 1;
for(int i = 0; i < 2; i++) if(ch[i][o])
ns[o].siz += ns[ch[i][o]].siz;
return ;
}
void rotate(int u) {
int y = fa[u], z = fa[y], l = 0, r = 1;
if(z) ch[ch[1][z]==y][z] = u;
if(ch[1][y] == u) swap(l, r);
fa[u] = z; fa[y] = u; fa[ch[r][u]] = y;
ch[l][y] = ch[r][u]; ch[r][u] = y;
maintain(y); maintain(u);
return ;
}
void insert(int& o, int v) {
if(!o) {
ns[o = getnode()] = Node(v, rand());
return maintain(o);
}
bool d = v > ns[o].v;
insert(ch[d][o], v); fa[ch[d][o]] = o;
if(ns[ch[d][o]].r > ns[o].r) {
int t = ch[d][o];
rotate(t); o = t;
}
return maintain(o);
}
void del(int& o, int v) {
if(!o) return ;
if(ns[o].v == v) {
if(!ch[0][o] && !ch[1][o]) rec = o, o = 0;
else if(!ch[0][o]) {
int t = ch[1][o]; fa[t] = fa[o]; rec = o; o = t;
}
else if(!ch[1][o]) {
int t = ch[0][o]; fa[t] = fa[o]; rec = o; o = t;
}
else {
bool d = ns[ch[1][o]].r > ns[ch[0][o]].r;
int t = ch[d][o]; rotate(t); o = t;
del(ch[d^1][o], v);
}
}
else {
bool d = v > ns[o].v;
del(ch[d][o], v);
}
return maintain(o);
}
int findlow(int o, int v) {
if(!o) return 0;
int ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
if(v > ns[o].v) return ls + 1 + findlow(ch[1][o], v);
return findlow(ch[0][o], v);
}
int findupp(int o, int v) {
if(!o) return 0;
int ls = ch[0][o] ? ns[ch[0][o]].siz : 0;
if(v >= ns[o].v) return ls + 1 + findupp(ch[1][o], v);
return findupp(ch[0][o], v);
} int rt[maxn<<2], val[maxn];
void Add(int L, int R, int o, int x) {
insert(rt[o], val[x]);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(x <= M) return Add(L, M, lc, x);
return Add(M+1, R, rc, x);
}
void Upd(int L, int R, int o, int x, int v) {
del(rt[o], val[x]); insert(rt[o], v);
if(L == R) return ;
int M = L + R >> 1, lc = o << 1, rc = lc | 1;
if(x <= M) return Upd(L, M, lc, x, v);
return Upd(M+1, R, rc, x, v);
}
int Que(int L, int R, int o, int ql, int qr, int v) {
if(ql <= L && R <= qr) return findupp(rt[o], v) - findlow(rt[o], v);
int M = L + R >> 1, lc = o << 1, rc = lc | 1, ans = 0;
if(ql <= M) ans += Que(L, M, lc, ql, qr, v);
if(qr > M) ans += Que(M+1, R, rc, ql, qr, v);
return ans;
} int n, m, head[maxn], next[maxm], to[maxm];
void AddEdge(int a, int b) {
to[++m] = b; next[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; next[m] = head[a]; head[a] = m;
return ;
}
int pa[maxn], son[maxn], dep[maxn], siz[maxn], top[maxn], W[maxn], ww;
void build(int u) {
siz[u] = 1;
for(int e = head[u]; e; e = next[e]) if(to[e] != pa[u]) {
pa[to[e]] = u;
dep[to[e]] = dep[u] + 1;
build(to[e]);
siz[u] += siz[to[e]];
if(!son[u] || siz[son[u]] < siz[to[e]]) son[u] = to[e];
}
return ;
}
void gett(int u, int tp) {
W[u] = ++ww; top[u] = tp;
if(son[u]) gett(son[u], tp);
for(int e = head[u]; e; e = next[e]) if(to[e] != pa[u] && to[e] != son[u])
gett(to[e], to[e]);
return ;
}
int query(int a, int b, int v) {
int f1 = top[a], f2 = top[b], ans = 0;
while(f1 != f2) {
if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b);
int tmp = Que(1, n, 1, W[f1], W[a], v);
ans += Que(1, n, 1, W[f1], W[a], v);
a = pa[f1]; f1 = top[a];
}
if(dep[a] < dep[b]) swap(a, b);
int tmp = Que(1, n, 1, W[b], W[a], v);
ans += Que(1, n, 1, W[b], W[a], v);
return ans;
} int T[maxn];
int main() {
n = read(); int q = read();
for(int i = 1; i <= n; i++) T[i] = read();
for(int i = 1; i < n; i++) {
int a = read(), b = read();
AddEdge(a, b);
}
build(1); gett(1, 1);
for(int i = 1; i <= n; i++) val[W[i]] = T[i];
for(int i = 1; i <= n; i++) Add(1, n, 1, i);
int lst = 0;
while(q--) {
char tp[2];
scanf("%s", tp);
if(tp[0] == 'C') {
int x = read() ^ lst, t = read() ^ lst;
Upd(1, n, 1, W[x], t); val[W[x]] = t;
}
if(tp[0] == 'Q') {
int a = read() ^ lst, b = read() ^ lst, t = read() ^ lst;
lst = query(a, b, t);
printf("%d\n", lst);
}
} return 0;
}

解法二:对于每一种颜色建一颗线段树,求一边 dfs 序把点修改链上询问转化成区间修改点询问的问题,线段树动态开节点防止爆炸。(别用 map 用 hash……)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 100010
#define maxm 200010
#define maxnode 10000010
int n, m, head[maxn], next[maxm], to[maxm], T[maxn]; #define MOD 233333
int Th, hd[MOD], nxt[maxn*3], Val[maxn*3];
int Find(int x) {
int v = (x % MOD + MOD) % MOD;
for(int e = hd[v]; e; e = nxt[e]) if(Val[e] == x) return e;
return 0;
}
void insert(int x) {
int v = (x % MOD + MOD) % MOD;
Val[++Th] = x; nxt[Th] = hd[v]; hd[v] = Th;
return ;
} void AddEdge(int a, int b) {
to[++m] = b; next[m] = head[a]; head[a] = m;
swap(a, b);
to[++m] = b; next[m] = head[a]; head[a] = m;
return ;
}
int fa[maxn], son[maxn], siz[maxn], dep[maxn], top[maxn], W[maxn], ww, dl[maxn], dr[maxn];
void build(int u) {
siz[u] = 1;
for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u]) {
fa[to[e]] = u;
dep[to[e]] = dep[u] + 1;
build(to[e]);
siz[u] += siz[to[e]];
if(!son[u] || siz[son[u]] < siz[to[e]]) son[u] = to[e];
}
return ;
}
void gett(int u, int tp) {
dl[u] = W[u] = ++ww; top[u] = tp;
if(son[u]) gett(son[u], tp);
for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u] && to[e] != son[u])
gett(to[e], to[e]);
dr[u] = ww;
return ;
}
int lca(int a, int b) {
int f1 = top[a], f2 = top[b];
while(f1 != f2) {
if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b);
a = fa[f1]; f1 = top[a];
}
return dep[a] < dep[b] ? a : b;
} int ToT, rt[maxn*3], lc[maxnode], rc[maxnode], S[maxnode], addv[maxnode];
void pushdown(int o, int L, int R) {
if(!addv[o]) return ;
S[o] += addv[o];
if(L < R) {
if(!lc[o]) lc[o] = ++ToT;
if(!rc[o]) rc[o] = ++ToT;
addv[lc[o]] += addv[o];
addv[rc[o]] += addv[o];
}
addv[o] = 0;
return ;
}
void update(int& o, int L, int R, int ql, int qr, int v) {
if(!o) o = ++ToT;
pushdown(o, L, R);
if(ql <= L && R <= qr) addv[o] += v;
else {
int M = L + R >> 1;
if(ql <= M) update(lc[o], L, M, ql, qr, v);
if(qr > M) update(rc[o], M+1, R, ql, qr, v);
}
return ;
}
int query(int o, int L, int R, int x) {
if(!x || !o) return 0;
pushdown(o, L, R);
if(L == R) return S[o];
int M = L + R >> 1;
if(x <= M) return query(lc[o], L, M, x);
return query(rc[o], M+1, R, x);
} int main() {
n = read(); int q = read();
for(int i = 1; i <= n; i++) {
T[i] = read();
if(!Find(T[i])) insert(T[i]);
}
// for(int i = 1; i <= n; i++) printf("%d%c", Find(T[i]), i < n ? ' ' : '\n');
for(int i = 1; i < n; i++) {
int a = read(), b = read();
AddEdge(a, b);
}
build(1); gett(1, 1);
// for(int i = 1; i <= n; i++) printf("%d: %d %d\n", i, dl[i], dr[i]);
for(int i = 1; i <= n; i++) update(rt[Find(T[i])], 1, n, dl[i], dr[i], 1);
int lst = 0;
while(q--) {
char Tp[2]; scanf("%s", Tp);
if(Tp[0] == 'C') {
int x = read() ^ lst, t = read() ^ lst;
update(rt[Find(T[x])], 1, n, dl[x], dr[x], -1);
T[x] = t; if(!Find(t)) insert(t);
update(rt[Find(t)], 1, n, dl[x], dr[x], 1);
}
if(Tp[0] == 'Q') {
int a = read() ^ lst, b = read() ^ lst, t = rt[Find(read()^lst)], c = lca(a, b);
int A = query(t, 1, n, W[a]), B = query(t, 1, n, W[b]), C = query(t, 1, n, W[c]), fC = query(t, 1, n, W[fa[c]]);
// printf("%d %d %d(%d) %d(%d)\n", A, B, C, c, fC, fa[c]);
lst = A + B - C - fC;
printf("%d\n", lst);
}
} return 0;
}

[COJ2201][KOJ0223][KOJ0250]花园的更多相关文章

  1. 二分+最短路判定 BZOJ 2709: [Violet 1]迷宫花园

    BZOJ 2709: [Violet 1]迷宫花园 Sample Input 5 ######### # # # # # # # #S# # ##### # # ## # # # ### ### ## ...

  2. BZOJ 1105: [POI2007]石头花园SKA

    1105: [POI2007]石头花园SKA Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 628  Solved: 182[Submit][Stat ...

  3. 读《CSS禅意花园》 有感

    1.图片用<img>标签添加到页面中,会增加页面的大小,导致页面加载需要更长的时间.可以用css background 引用图片. 1.1.若图像属于“内容”而不是“样式”的一部分,例如“ ...

  4. 洛谷教主花园dp

    洛谷-教主的花园-动态规划   题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价 ...

  5. 洛谷P1357 花园(状态压缩 + 矩阵快速幂加速递推)

    题目链接:传送门 题目: 题目描述 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(<=N<=^).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻 ...

  6. 洛谷P1133 教主的花园

    题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树 ...

  7. 2018.08.30 花园(期望dp)

    题目背景 SCOI2017 DAY2 T1 题目描述 小 A 的花园的长和宽分别是 L,H .小 A 喜欢在花园里做游戏.每次做游戏的时候,他都先把花园均匀分割成 L×H 个小方块,每个方块的长和宽都 ...

  8. 洛谷 P1357 花园 解题报告

    P1357 花园 题目描述 小\(L\)有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为\(1~N(2<=N<=10^{15})\).他的环形花园每天都会换一个新花样,但他的花园都不 ...

  9. BZOJ1105 [POI2007]石头花园SKA 贪心

    [POI2007]石头花园SKA Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 776  Solved: 237[Submit][Status][Di ...

随机推荐

  1. ActiveMQ笔记(6):消息延时投递

    在开发业务系统时,某些业务场景需要消息定时发送或延时发送(类似:飞信的短信定时发送需求),这时候就需要用到activemq的消息延时投递,详细的文档可参考官网说明,本文只介绍二种常用的用法: 注:本文 ...

  2. 大众点评cat系统的搭建笔记

    项目地址:https://github.com/dianping/cat 编译步骤: 这个项目比较另类,把编译需要的jar包,单独放在git分支mvn-repo里了,而且官方文档里给了一个错误的命令提 ...

  3. [LeetCode] House Robber III 打家劫舍之三

    The thief has found himself a new place for his thievery again. There is only one entrance to this a ...

  4. [LeetCode] Alien Dictionary 另类字典

    There is a new alien language which uses the latin alphabet. However, the order among letters are un ...

  5. Goodbye 2016 总结与展望

    今天居然是2016年的最后一天了,写点什么回忆吧. 2016开始的时候我刚拿到普及组一等奖,还只是压线,水平很差.学校并不知道这有多差,于是狠狠宣传这所谓的"光荣事迹".那段时间我 ...

  6. CentOS下配置java环境变量classpath

    一. 需要配置的环境变量1. PATH环境变量.作用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序.我们需要把 jdk安装目录下的bin ...

  7. IFC是什么

    IFC是用EXPRESS语言来描述的一种数据格式 IFC的物理文件 为了数据交换的目的,STEP标准Prat 21规定了正文文件的结构,认为一个STEP文件或一个Part 21文件包括两端:头段和数据 ...

  8. linux设置定时备份mysql数据库

    最近写自己的项目,买了阿里云服务器,可以在云上根据自己想到的需求随意使用技术,感觉很爽.备份mysql流程如下: 环境:CentOS Linux release 7.2.1511 (Core) mys ...

  9. smtplib.SMTPAuthenticationError: (535, b'Error: authentication failed')解决办法

    raise SMTPAuthenticationError(code, resp) smtplib.SMTPAuthenticationError: (535, b'Error: authentica ...

  10. CodeForces - 662A Gambling Nim

    http://codeforces.com/problemset/problem/662/A 题目大意: 给定n(n <= 500000)张卡片,每张卡片的两个面都写有数字,每个面都有0.5的概 ...