• [BZOJ2908]又是nand


    [BZOJ2908]又是nand

    试题描述

    首先知道A nand B=not(A and B) (运算操作限制了数位位数为K)比如2 nand 3,K=3,则2 nand 3=not (2 and 3)=not 2=5。
    给出一棵树,树上每个点都有点权,定义树上从a到b的费用为0与路径上的点的权值顺次nand的结果,例如:从2号点到5号点顺次经过2->3->5,权值分别为5、7、2,K=3,那么最终结果为0 nand 5 nand 7 nand 2=7 nand 7 nand 2=0 nand 2=7,现在这棵树需要支持以下操作。
    ①    Replace a b:将点a(1≤a≤N)的权值改为b。
    ②    Query a b:输出点a到点b的费用。
    请众神给出一个程序支持这些操作。

    输入

    第一行N,M,K,树的节点数量、总操作个数和运算位数。
    接下来一行N个数字,依次表示节点i的权值。
    接下来N-1行,每行两个数字a,b(1≤a,b≤N)表示a,b间有一条树边。
    接下来M行,每行一个操作,为以上2类操作之一。

    输出

    对于操作②每个输出一行,如题目所述。

    输入示例

    3 3 3
    2 7 3
    1 2
    2 3
    Query 2 3
    Replace 1 3
    Query 1 1

    输出示例

    4
    7

    数据规模及约定

    100%的数据N、M≤100000,K≤32

    题解

    线段树题强行套在树上。。。

    注意到 nand 运算没有结合律,所以不能直接维护。进一步分析发现 0 nand x = x nand 0 = 1 (x ∈ {0, 1}),所以我们只用关心一条路径上最后一个 0 的位置,然后数它后面 1 的个数,分奇偶性讨论一下就可以了。注意整条链权值都是 1 的情况特殊处理一下。什么你说我上面只讨论了一位二进制的情况?因为最多不超过 32 位,所以我们建 32 棵线段树就好了。

    还有,因为询问有方向,所以线段树需要维护区间中最后一个和最靠前一个 0 的位置。

    #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;
    #define LL long long
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
    	if(Head == Tail) {
    		int l = fread(buffer, 1, BufferSize, stdin);
    		Tail = (Head = buffer) + l;
    	}
    	return *Head++;
    }
    LL read() {
    	LL 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 100005
    #define maxm 200005
    int n, q, k, m, head[maxn], next[maxm], to[maxm];
    LL val[maxn];
    
    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 siz[maxn], son[maxn], fa[maxn], dep[maxn], top[maxn], pos[maxn], w, qos[maxn];
    void build(int u) {
    	siz[u] = 1;
    	for(int e = head[u]; e; e = next[e]) if(fa[u] != to[e]) {
    		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 build(int u, int tp) {
    	pos[u] = ++w; top[u] = tp; qos[w] = u;
    	if(son[u]) build(son[u], tp);
    	for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u] && to[e] != son[u])
    		build(to[e], to[e]);
    	return ;
    }
    
    int mx[33][maxn<<2], mn[33][maxn<<2];
    LL V[maxn];
    void build(int t, int L, int R, int o) {
    	if(L == R) {
    		int x = V[L] - (V[L] >> (LL)t + 1ll << (LL)t + 1ll) >> (LL)t;
    		if(x) mx[t][o] = -1, mn[t][o] = n + 1;
    		else mx[t][o] = mn[t][o] = L;
    		return ;
    	}
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
    	build(t, L, M, lc); build(t, M+1, R, rc);
    	mx[t][o] = max(mx[t][lc], mx[t][rc]);
    	mn[t][o] = min(mn[t][lc], mn[t][rc]);
    	return ;
    }
    void update(int t, int L, int R, int o, int p) {
    	if(L == R) {
    		int x = V[L] - (V[L] >> (LL)t + 1ll << (LL)t + 1ll) >> (LL)t;
    		if(x) mx[t][o] = -1, mn[t][o] = n + 1;
    		else mx[t][o] = mn[t][o] = L;
    		return ;
    	}
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
    	if(p <= M) update(t, L, M, lc, p);
    	else update(t, M+1, R, rc, p);
    	mx[t][o] = max(mx[t][lc], mx[t][rc]);
    	mn[t][o] = min(mn[t][lc], mn[t][rc]);
    	return ;
    }
    int ql, qr;
    int querymx(int t, int L, int R, int o) {
    	if(ql <= L && R <= qr) return mx[t][o];
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1, ans = -1;
    	if(ql <= M) ans = max(ans, querymx(t, L, M, lc));
    	if(qr > M) ans = max(ans, querymx(t, M+1, R, rc));
    	return ans;
    }
    int querymn(int t, int L, int R, int o) {
    	if(ql <= L && R <= qr) return mn[t][o];
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1, ans = n + 1;
    	if(ql <= M) ans = min(ans, querymn(t, L, M, lc));
    	if(qr > M) ans = min(ans, querymn(t, M+1, R, rc));
    	return ans;
    }
    int lca(int a, int b) {
    	int f1 = top[a], f2 = top[b];
    //	puts("lcahere");
    	while(f1 != f2) {
    //		printf("%d %d %d %d
    ", a, f1, b, f2);
    		if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b);
    		a = fa[f1]; f1 = top[a];
    	}
    	if(dep[a] > dep[b]) swap(a, b);
    	return a;
    }
    int last[40], last2[40];
    LL query(int a, int b) {
    	memset(last, -1, sizeof(last));
    	memset(last2, -1, sizeof(last2));
    	int c = lca(a, b), f1 = top[a], f2 = top[b], A = a, B = b;
    //	puts("here");
    	while(f1 != top[c]) {
    		ql = pos[f1]; qr = pos[a];
    		for(int i = 0; i < k; i++) {
    			int tmp = querymn(i, 1, n, 1);
    			if(tmp <= n) last[i] = qos[tmp];
    		}
    		a = fa[f1]; f1 = top[a];
    	}
    	ql = pos[c]; qr = pos[a];
    	for(int i = 0; i < k; i++) {
    		int tmp = querymn(i, 1, n, 1);
    		if(tmp <= n) last[i] = qos[tmp];
    	}
    	while(f2 != top[c]) {
    		ql = pos[f2]; qr = pos[b];
    		for(int i = 0; i < k; i++) {
    			int tmp = querymx(i, 1, n, 1);
    			if(last2[i] < 0 && tmp >= 0) last2[i] = qos[tmp];
    		}
    		b = fa[f2]; f2 = top[b];
    	}
    	ql = pos[c]; qr = pos[b];
    	for(int i = 0; i < k; i++) {
    		int tmp = querymx(i, 1, n, 1);
    		if(last2[i] < 0 && tmp >= 0) last2[i] = qos[tmp];
    	}
    	
    //	for(int i = 0; i < k; i++) printf("%d ", last[i]); putchar('
    ');
    //	for(int i = 0; i < k; i++) printf("%d ", last2[i]); putchar('
    ');
    	LL ret = 0;
    //	printf("lca: %d
    ", c);
    	for(int i = 0; i < k; i++) {
    		int dis;
    		if(last[i] < 0 && last2[i] < 0) dis = dep[A] + dep[B] - dep[c] - dep[c];
    		else {
    			if(last2[i] >= 0) dis = dep[B] - dep[last2[i]];
    			else dis = dep[last[i]] + dep[B] - dep[c] - dep[c];
    		}
    //		printf("%d ", dis);
    		ret |= ((((LL)dis & 1ll) ^ 1ll) << (LL)i);
    	}
    //	putchar('
    ');
    	return ret;
    }
    
    int main() {
    	n = read(); q = read(); k = read();
    	for(int i = 1; i <= n; i++) val[i] = read();
    	for(int i = 1; i < n; i++) {
    		int a = read(), b = read();
    		AddEdge(a, b);
    	}
    	
    	build(1);
    	build(1, 1);
    	for(int i = 1; i <= n; i++) V[pos[i]] = val[i];
    	for(int i = 0; i < k; i++) build(i, 1, n, 1);
    	while(q--) {
    		char tp = Getchar();
    		while(!isalpha(tp)) tp = Getchar();
    		LL a = read(), b = read();
    		if(tp == 'Q') printf("%lld
    ", query(a, b));
    		if(tp == 'R') {
    			V[pos[a]] = b;
    			for(int i = 0; i < k; i++) update(i, 1, n, 1, pos[a]);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    用javascript实现html页面之间的参数传递
    个性的研究
    [luogu1967] 货车运输
    mscorwks.dll 没有被指定在Windows上运行,错误状态 0xc000012f
    dom4j解析xml时报:系统找不到指定路径
    The strip's most beautiful gril,rendezvous never a cover;
    无法在自定义编辑器中开发TransactSQL文件
    Default code generation is disabled for model。。。
    使用IE9艰辛历程之从什么网页都打不开到什么都秒开的传奇
    Metro IE10快捷方式 不小心删了
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5801962.html
Copyright © 2020-2023  润新知