• 题解 SP6779 【GSS7


    题目传送门

    题目大意

    给出一个(n)个点的树,每个点有权值。有(m)次操作,每次要么查询一条链上的最大子段和,要么把一条链的权值都修改为一个常数。

    (n,mle 10^5)

    思路

    如果是一维的话,我们不难列出动态( exttt{dp})转移式:

    [egin{bmatrix}0&a_i&0\-infty&a_i&0\-infty&-infty&0end{bmatrix}egin{bmatrix}g_{i-1}\f_{i-1}\0end{bmatrix}=egin{bmatrix}g_i\f_i\0end{bmatrix} ]

    不懂得话可以去看一下GSS1的题解。

    这道题要求一个链的答案,那我们直接求出这个链的矩阵之积即可,用树剖就好了,修改也很简单。需要注意的是,矩阵乘法有没有交换律的,所以需要维护两种不同方向的矩阵之积。

    这道题有点卡常,所以快速幂不能朴素快速幂,而是找一下规律,具体见代码。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define INF 0x7f7f7f7f
    #define MAXN 100005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n,m,wei[MAXN];
    
    struct Matrix{
    	int val[3][3];
    	Matrix(){memset (val,0xcf,sizeof (val));}
    	int* operator [](int x){return val[x];}
    	Matrix operator * (const Matrix &p)const{
    		Matrix New;
    		for (Int i = 0;i < 3;++ i)
    			for (Int j = 0;j < 3;++ j)
    				for (Int k = 0;k < 3;++ k)
    					New[i][j] = max (New[i][j],val[i][k] + p.val[k][j]);
    		return New;
    	}
    };
    
    Matrix init (int v){
    	Matrix A;
    	A[0][0] = A[0][2] = A[1][2] = A[2][2] = 0,A[0][1] = A[1][1] = v;
    	return A;
    }
    
    Matrix III (){
    	Matrix res;
    	for (Int i = 0;i < 3;++ i) res[i][i] = 0;
    	return res;
    }
    
    Matrix qkpow (int v,int k){
    	Matrix A;
    	A[0][0] = A[2][2] = 0;
    	A[0][1] = max (v,k * v),A[0][2] = A[1][2] = max (0,k * v);
    	A[1][1] = k * v;
    	return A;
    }
    
    struct edge{
    	int v,nxt;
    }e[MAXN << 1];
    
    int toop = 1,head[MAXN];
    
    void Add_Edge (int u,int v){
    	e[++ toop] = edge {v,head[u]},head[u] = toop;
    	e[++ toop] = edge {u,head[v]},head[v] = toop;
    }
    
    int Index,dep[MAXN],siz[MAXN],son[MAXN],dfn[MAXN],par[MAXN],top[MAXN],tur[MAXN];
    
    void dfs1 (int u,int fa){
    	par[u] = fa,dep[u] = dep[fa] + 1,siz[u] = 1;
    	for (Int i = head[u];i;i = e[i].nxt){
    		int v = e[i].v;
    		if (v == fa) continue;
    		dfs1 (v,u),siz[u] += siz[v];
    		if (siz[v] > siz[son[u]]) son[u] = v;
    	}
    }
    
    void dfs2 (int u,int Top){
    	dfn[u] = ++ Index,tur[Index] = u,top[u] = Top;
    	if (son[u]) dfs2 (son[u],Top);
    	for (Int i = head[u];i;i = e[i].nxt){
    		int v = e[i].v;
    		if (v == par[u] || v == son[u]) continue;
    		dfs2 (v,v);
    	}
    }
    
    struct Segment{
    #define len(x) (tree[x].r-tree[x].l+1)
    	struct node{
    		int l,r,tag;Matrix Sum[2];
    	}tree[MAXN << 2];
    	void Pushup (int x){
    		tree[x].Sum[0] = tree[x << 1].Sum[0] * tree[x << 1 | 1].Sum[0];
    		tree[x].Sum[1] = tree[x << 1 | 1].Sum[1] * tree[x << 1].Sum[1];
    	}
    	void Pushadd (int x,int v){
    		tree[x].tag = v;
    		tree[x].Sum[0] = tree[x].Sum[1] = qkpow (v,len (x));
    	}
    	void Pushdown (int x){
    		if (tree[x].tag == INF) return ;
    		Pushadd (x << 1,tree[x].tag),Pushadd (x << 1 | 1,tree[x].tag);
    		tree[x].tag = INF; 
    	}
    	void build (int i,int l,int r){
    		tree[i].l = l,tree[i].r = r,tree[i].tag = INF;
    		if (l == r) return tree[i].Sum[0] = tree[i].Sum[1] = init(wei[tur[l]]),void ();
    		int mid = (l + r) >> 1;
    		build (i << 1,l,mid),build (i << 1 | 1,mid + 1,r);
    		Pushup (i);
    	}
    	Matrix query (int i,int l,int r,int type){
    		if (tree[i].l >= l && tree[i].r <= r) return tree[i].Sum[type];
    		int mid = (tree[i].l + tree[i].r) >> 1;
    		Pushdown (i);
    		if (r <= mid) return query (i << 1,l,r,type);
    		else if (l > mid) return query (i << 1 | 1,l,r,type);
    		else return !type ? query (i << 1,l,r,type) * query (i << 1 | 1,l,r,type) : query (i << 1 | 1,l,r,type) * query (i << 1,l,r,type);
    	}
    	void Change (int i,int l,int r,int v){
    		if (tree[i].l >= l && tree[i].r <= r) return Pushadd (i,v);
    		int mid = (tree[i].l + tree[i].r) >> 1;
    		Pushdown (i);
    		if (l <= mid) Change (i << 1,l,r,v);
    		if (r > mid) Change (i << 1 | 1,l,r,v);
    		Pushup (i);
    	}
    #undef len(x)
    }Tree;
    
    int QueryChain (int x,int y){
    	Matrix A,B;A = B = III();
    	while (top[x] ^ top[y]){
    		if (dep[top[x]] > dep[top[y]]){
    			A = A * Tree.query (1,dfn[top[x]],dfn[x],1);
    			x = par[top[x]]; 
    		}
    		else{
    			B = Tree.query (1,dfn[top[y]],dfn[y],0) * B;
    			y = par[top[y]]; 
    		}
    	}
    	if (dfn[x] < dfn[y]) B = Tree.query (1,dfn[x],dfn[y],0) * B;
    	else A = A * Tree.query (1,dfn[y],dfn[x],1);A = A * B;
    	return max (A[0][1],A[0][2]); 
    }
    
    void UpdateChain (int x,int y,int v){
    	while (top[x] ^ top[y]){
    		if (dep[top[x]] < dep[top[y]]) swap (x,y);
    		Tree.Change (1,dfn[top[x]],dfn[x],v);
    		x = par[top[x]]; 
    	}
    	if (dfn[x] > dfn[y]) swap (x,y);
    	Tree.Change (1,dfn[x],dfn[y],v);
    }
    
    signed main(){
    	read (n);
    	for (Int i = 1;i <= n;++ i) read (wei[i]);
    	for (Int i = 2,u,v;i <= n;++ i) read (u,v),Add_Edge (u,v);
    	dfs1 (1,0),dfs2 (1,1),Tree.build (1,1,n);
    	read (m);
    	while (m --){
    		int opt,a,b,c;
    		read (opt,a,b);
    		if (opt == 1) write (QueryChain (a,b)),putchar ('
    ');
    		else read (c),UpdateChain (a,b,c);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Iscroll滑动无效
    原生js 无缝滚动组件
    原生 js dialog弹窗组件
    html5 历史管理
    html5拖拽属性
    highcharts 数据图设置X轴间隔显示效果
    highcharts柱状图含有正负柱设置不同颜色的方法
    移动端滑动插件 swiper
    千分位添加和去掉方法
    dubbo常用类和路径
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13385790.html
Copyright © 2020-2023  润新知