• 【BZOJ】1036: [ZJOI2008]树的统计Count(lct/树链剖分)


    http://www.lydsy.com/JudgeOnline/problem.php?id=1036

    lct:

    (ps:为嘛我的那么慢T_T,不知道排到哪了。。难道别人都是树剖吗。。。看来有必要学 orz

    裸的lct,这里只说一下找路径就行了。,。算了,上晚修去了,待会回来更

     lca大家应该都会求,就是2次access就行了(很容易理解的)

    然后我们求路径的时候,用lca的右子女的值和lca自身的值和第一次access的点的值来更新就行了,

    但是这里有特殊情况,就是lca==第一次access的点的情况,因为这是第一个点是第二个点的父亲,那么直接用lca的值就能更新,再用第一个点的值来更新就重复了。

    (为什么lca==第二次access的点不需要判呢。。自己想把。很简单)

    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define dbg(x) cout << #x << "=" << x << endl
    #define read(x) x=getint()
    #define print(x) printf("%d", x)
    #define max(a,b) ((a)>(b)?(a):(b))
    
    const int oo=~0u>>1;
    inline int getint() { char c; int ret=0, k=1; for(c=getchar(); c<'0' || c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return k*ret; }
    const int N=30010, M=100005;
    int ihead[N], inext[M], to[M], cnt, q[N], front, tail, n, m;
    bool vis[N];
    
    struct node* null;
    struct node {
    	node* fa, *ch[2];
    	int w, sum, mx;
    	bool d() { return fa->ch[1]==this; }
    	bool check() { return fa->ch[0]!=this && fa->ch[1]!=this; }
    	void setc(node* c, bool d) { ch[d]=c; c->fa=this; }
    	void pushup() { 
    		sum=w+ch[0]->sum+ch[1]->sum;
    		mx=max(w, max(ch[0]->mx, ch[1]->mx));
    	}
    }*nd[N];
    
    inline void rot(node* r) {
    	node* fa=r->fa; bool d=r->d();
    	if(fa->check()) r->fa=fa->fa;
    	else fa->fa->setc(r, fa->d());
    	fa->setc(r->ch[!d], d);
    	r->setc(fa, !d);
    	fa->pushup();
    }
    
    inline void splay(node* r) {
    	while(!r->check())
    		if(r->fa->check()) rot(r);
    		else r->d()==r->fa->d()?(rot(r->fa), rot(r)):(rot(r), rot(r));
    	r->pushup();
    }
    
    inline node* access(node* fa) {
    	node* c=null;
    	for(; fa!=null; c=fa, fa=fa->fa) {
    		splay(fa);
    		fa->setc(c, 1);
    		fa->pushup();
    	}
    	return c;
    }
    
    inline void bfs() {
    	vis[1]=1; int u, v, i;
    	front=tail=0; q[tail++]=1;
    	while(front!=tail) {
    		u=q[front++];
    		for(i=ihead[u]; i; i=inext[i]) if(!vis[v=to[i]]) {
    			vis[v]=1;
    			nd[v]->fa=nd[u];
    			q[tail++]=v;
    		}
    	}
    }
    
    inline void add(const int &u, const int &v) {
    	inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v;
    	inext[++cnt]=ihead[v]; ihead[v]=cnt; to[cnt]=u;
    }
    
    int main() {
    	null=new node; null->fa=null->ch[0]=null->ch[1]=null; null->w=null->sum=0; null->mx=oo+1;
    	read(n);
    	int u, v, t;
    	for(int i=1; i<n; ++i) {
    		read(u); read(v);
    		add(u, v);
    	}
    	int w;
    	for(int i=1; i<=n; ++i) {
    		nd[i]=new node;
    		read(w);
    		nd[i]->w=w;
    		nd[i]->ch[0]=nd[i]->ch[1]=nd[i]->fa=null;
    	}
    	bfs();
    	char c[10];
    	node* lca=null;
    	read(m);
    	int ans;
    	for(int i=0; i<m; ++i) {
    		scanf("%s", c);
    		if(c[0]=='C') {
    			read(u); read(t);
    			splay(nd[u]);
    			nd[u]->w=t;
    			nd[u]->pushup();
    		}
    		else if(c[0]=='Q') {
    			read(u); read(v);
    			access(nd[u]);
    			lca=access(nd[v]);
    			splay(nd[u]);
    			if(nd[u]==lca) {
    				if(c[1]=='M') ans=max(lca->w, lca->ch[1]->mx);
    				else ans=lca->w + lca->ch[1]->sum;
    			}
    			else {
    				if(c[1]=='M') ans=max(max(lca->w, nd[u]->mx), lca->ch[1]->mx);
    				else ans=lca->w + lca->ch[1]->sum + nd[u]->sum;
    			}
    			printf("%d
    ", ans);
    		}
    	}
    	return 0;
    }
    

    树链剖分,裸模板题:

    好慢啊

    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define dbg(x) cout << #x << "=" << x << endl
    #define read(x) x=getint()
    #define print(x) printf("%d", x)
    #define lc x<<1
    #define rc x<<1|1
    #define lson l, m, lc
    #define rson m+1, r, rc
    #define MID (l+r)>>1
    
    const int oo=~0u>>1;
    inline int getint() { char c; int ret=0, k=1; for(c=getchar(); c<'0' || c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return k*ret; }
    
    const int N=30010, M=100005;
    int ihead[N], inext[M], to[M], cnt, n, m;
    int top[N], son[N], fa[N], dep[N], sz[N], id[N], a[N], b[N], tot;
    int L, R, key;
    
    struct node { int mx, sum; }t[N*50];
    inline const int max(const int& a, const int& b) { return a>b?a:b; }
    inline void pushup(const int &x) { t[x].mx=max(t[lc].mx, t[rc].mx); t[x].sum=t[lc].sum+t[rc].sum; }
    
    void dfs1(const int &u) {
    	sz[u]=1; int v;
    	for(int i=ihead[u]; i; i=inext[i]) if(fa[u]!=(v=to[i])) {
    		fa[v]=u;
    		dep[v]=dep[u]+1;
    		dfs1(v);
    		sz[u]+=sz[v];
    		if(sz[v]>sz[son[u]]) son[u]=v;
    	}
    }
    
    void dfs2(const int &u, const int &tp) {
    	id[u]=++tot; top[u]=tp; b[tot]=a[u];
    	if(son[u]) dfs2(son[u], tp);
    	for(int i=ihead[u]; i; i=inext[i]) if(to[i]!=fa[u] && to[i]!=son[u]) dfs2(to[i], to[i]);
    }
    
    void build(const int &l, const int &r, const int &x) {
    	if(l==r) { t[x].mx=t[x].sum=b[l]; return; }
    	int m=MID;
    	build(lson); build(rson);
    	pushup(x); 
    }
    
    void update(const int &l, const int &r, const int &x) {
    	if(l==r) { t[x].mx=t[x].sum=key; return; }
    	int m=MID;
    	if(L<=m) update(lson);
    	if(m<R) update(rson);
    	pushup(x); 
    }
    
    int getmax(const int &l, const int &r, const int &x) {
    	if(L<=l && r<=R) return t[x].mx;
    	int m=MID, mx=oo+1;
    	if(L<=m) mx=max(mx, getmax(lson));
    	if(m<R) mx=max(mx, getmax(rson));
    	return mx;
    }
    
    int query(const int &l, const int &r, const int &x) {
    	if(L<=l && r<=R) return t[x].sum;
    	int m=MID, ret=0;
    	if(L<=m) ret+=query(lson);
    	if(m<R) ret+=query(rson);
    	return ret;
    }
    
    inline int getmax(int x, int y) {
    	int fx=top[x], fy=top[y], ret=oo+1;
    	while(fx!=fy) {
    		if(dep[fx]<dep[fy]) { swap(x, y); swap(fx, fy); }
    		L=id[fx], R=id[x];
    		ret=max(ret, getmax(1, n, 1));
    		x=fa[fx]; fx=top[x];
    	}
    	if(dep[x]>dep[y]) swap(x, y);
    	L=id[x], R=id[y];
    	return max(ret, getmax(1, n, 1));
    }
    
    inline int query(int x, int y) {
    	int fx=top[x], fy=top[y], ret=0;
    	while(fx!=fy) {
    		if(dep[fx]<dep[fy]) { swap(x, y); swap(fx, fy); }
    		L=id[fx], R=id[x];
    		ret+=query(1, n, 1);
    		x=fa[fx]; fx=top[x];
    	}
    	if(dep[x]>dep[y]) swap(x, y);
    	L=id[x], R=id[y];
    	return ret+query(1, n, 1);
    }
    
    inline void add(const int &u, const int &v) {
    	inext[++cnt]=ihead[u]; ihead[u]=cnt; to[cnt]=v;
    	inext[++cnt]=ihead[v]; ihead[v]=cnt; to[cnt]=u;
    }
    
    int main() {
    	read(n);
    	int u, v, ans;
    	for(int i=1; i<n; ++i) {
    		read(u); read(v);
    		add(u, v);
    	}
    	for(int i=1; i<=n; ++i) read(a[i]);
    	dfs1(1);
    	dfs2(1, 1);
    	build(1, n, 1);
    	char c[10];
    	read(m);
    	for(int i=0; i<m; ++i) {
    		scanf("%s", c);
    		if(c[0]=='C') {
    			read(u); read(key); L=R=id[u];
    			update(1, n, 1);
    		}
    		else if(c[0]=='Q') {
    			read(u); read(v);
    			if(c[1]=='M') ans=getmax(u, v);
    			else ans=query(u, v);
    			printf("%d
    ", ans);
    		}
    	}
    	return 0;
    }
    

    Description

    一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

    Input

    输 入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数 q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到 30000之间。

    Output

    对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

    Sample Input

    4
    1 2
    2 3
    4 1
    4 2 1 3
    12
    QMAX 3 4
    QMAX 3 3
    QMAX 3 2
    QMAX 2 3
    QSUM 3 4
    QSUM 2 1
    CHANGE 1 5
    QMAX 3 4
    CHANGE 3 6
    QMAX 3 4
    QMAX 2 4
    QSUM 3 4

    Sample Output

    4
    1
    2
    2
    10
    6
    5
    6
    5
    16

    HINT

    Source

  • 相关阅读:
    Leetcode刷题记录:构建最大数二叉树
    Leetcode刷题记录:编码并解码短网址
    Python获取数字的二进制值
    SQL文件的BOM问题导致的invalid character错误及解决
    修改服务的运行权限,解决SVN Post Commit问题
    将iPod中的音乐拷贝到Mac中
    Linux下创建可执行bin安装文件
    Mac下使用XLD转换无损音乐Ape
    Mac环境下配置Tomcat+Eclipse
    Curl操作Elasticsearch的常用方法
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3916741.html
Copyright © 2020-2023  润新知