BZOJ 3531 旅行【树链剖分】

2024-08-24 11:32
文章标签 bzoj 树链 剖分 旅行 3531

本文主要是介绍BZOJ 3531 旅行【树链剖分】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[Sdoi2014]
简单的树链剖分
以每个信仰应该建一个线段树,空间复杂度为 O(5×1010)
因此会爆空间,所以需要动态申请空间。

//      whn6325689
//      Mr.Phoebe
//      http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<62
#define speed std::ios::sync_with_stdio(false);typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;#define CLR(x,y) memset(x,y,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define clr(a,x,sz) memset(a,x,sizeof(a[0])*(sz))
#define cpy(a,x,sz) memcpy(a,x,sizeof(a[0])*(sz))
#define debug(a) cout << #a" = " << (a) << endl;
#define debugarry(a, n) for (int i = 0; i < (n); i++) { cout << #a"[" << i << "] = " << (a)[i] << endl; }#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))#define MID(x,y) (x+((y-x)>>1))
#define getidx(l,r) (l+r | l!=r)
#define ls getidx(l,mid)
#define rs getidx(mid+1,r)
#define lson l,mid
#define rson mid+1,rtemplate<class T>
inline bool read(T &n)
{T x = 0, tmp = 1;char c = getchar();while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();if(c == EOF) return false;if(c == '-') c = getchar(), tmp = -1;while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();n = x*tmp;return true;
}
template <class T>
inline void write(T n)
{if(n < 0){putchar('-');n = -n;}int len = 0,data[20];while(n){data[len++] = n%10;n /= 10;}if(!len) data[len++] = 0;while(len--) putchar(data[len]+48);
}
//-----------------------------------const int MAXN=100010;struct SegTree *nil;struct SegTree
{SegTree *son[2];int maxn,sum;SegTree(){maxn=sum=0;son[0]=son[1]=nil;}void update(int l,int r,int x,int c){if(l==r){maxn=sum=c;return;}int mid=MID(l,r);if(x<=mid){if(son[0]==nil)son[0]=new SegTree();son[0]->update(lson,x,c);}else{if(son[1]==nil)son[1]=new SegTree();son[1]->update(rson,x,c);}maxn=max(son[0]->maxn,son[1]->maxn);sum=son[0]->sum+son[1]->sum;}int GetSum(int l,int r,int x,int y){if(this==nil) return 0;if(l==x && y==r)    return sum;int mid=MID(l,r);if(y <= mid) return son[0]->GetSum(lson,x,y);if(x > mid)      return son[1]->GetSum(rson,x,y);int left=son[0]->GetSum(lson,x,mid);int right=son[1]->GetSum(rson,mid+1,y);return left + right;}int GetMax(int l,int r,int x,int y){if(this==nil) return 0;if(l==x && y==r)    return maxn;int mid=MID(l,r);if(y <= mid) return son[0]->GetMax(lson,x,y);if(x > mid)      return son[1]->GetMax(rson,x,y);int left=son[0]->GetMax(lson,x,mid);int right=son[1]->GetMax(rson,mid+1,y);return max(left,right);}
} none,*root[MAXN];int n,m;
struct Edge
{int to,next;
} e[MAXN<<1];
int head[MAXN],tot;void init()
{CLR(head,-1);tot=0;nil=&none;
}inline void addedge(int x,int y)
{e[tot].next=head[x];e[tot].to=y;head[x]=tot++;
}int p[MAXN],belief[MAXN];
char str[22];
int sz[MAXN],son[MAXN],fa[MAXN],dep[MAXN];
int top[MAXN],dfn[MAXN],cnt;void dfs(int x,int last)
{dep[x]=dep[last]+1;fa[x]=last;son[x]=-1;sz[x]=1;int max_sz=0;for(int i=head[x]; ~i; i=e[i].next){if(e[i].to==last)  continue;dfs(e[i].to,x);sz[x]+=sz[e[i].to];if(sz[e[i].to]>max_sz)max_sz=sz[e[i].to],son[x]=e[i].to;}
}void getid(int x,int _top)
{dfn[x]=++cnt;top[x]=_top;if(~son[x])  getid(son[x],_top);for(int i=head[x]; ~i; i=e[i].next){if(e[i].to==fa[x] || e[i].to==son[x])  continue;getid(e[i].to,e[i].to);}
}inline int GetSum(int x,int y,int p)
{int re=0;while(top[x]!=top[y]){if(dep[top[x]] < dep[top[y]])  swap(x,y);re+=root[p]->GetSum(1,n,dfn[top[x]],dfn[x]);x=fa[top[x]];}if(dep[x]<dep[y])    swap(x,y);re += root[p]->GetSum(1,n,dfn[y],dfn[x]);return re;
}inline int GetMax(int x,int y,int p)
{int re=0;while(top[x] != top[y]){if(dep[top[x]] < dep[top[y]])  swap(x,y);re=max(re,root[p]->GetMax(1,n,dfn[top[x]],dfn[x]));x=fa[top[x]];}if(dep[x]<dep[y])    swap(x,y);re=max(re,root[p]->GetMax(1,n,dfn[y],dfn[x]));return re;
}int main()
{init();scanf("%d %d",&n,&m);for(int i=0; i<MAXN; i++)root[i]=new SegTree();for(int i=1; i<=n; i++)scanf("%d %d",&p[i],&belief[i]);for(int x,y,i=1; i<n; i++){scanf("%d %d",&x,&y);addedge(x,y),addedge(y,x);}dfs(1,0);getid(1,1);for(int i=1; i<=n; i++)root[belief[i]]->update(1,n,dfn[i],p[i]);for(int x,y,i=1; i<=m; i++){scanf("%s%d%d",str,&x,&y);if(str[0]=='C' && str[1]=='C'){root[belief[x]]->update(1,n,dfn[x],0);root[belief[x]=y]->update(1,n,dfn[x],p[x]);}else if(str[0]=='C' && str[1]=='W')root[belief[x]]->update(1,n,dfn[x],p[x]=y);else if(str[0]=='Q' && str[1]=='S')printf("%d\n",GetSum(x,y,belief[x]));elseprintf("%d\n",GetMax(x,y,belief[x]));}return 0;
}

这篇关于BZOJ 3531 旅行【树链剖分】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1102353

相关文章

社交平台找旅游搭子一起旅行靠谱吗?答案是不要太爽!

哈喽小伙伴们,今天要跟大家分享一个超级棒的小程序——咕哇找搭子!作为一个热爱自由行的人,最头疼的就是找不到志同道合的小伙伴。但自从用了这个咕哇小程序后,一切都变得简单又充满乐趣啦!🎉 上个月,我计划去云南旅行,就试着在咕哇上发布了我的行程信息。没想到很快就收到了几位朋友的回应,其中一位叫小莲的朋友特别投缘。我们不仅目的地一样,就连兴趣爱好都出奇地相似,于是我们就决定一起出发啦!👭

旅行商问题 | Matlab基于混合粒子群算法GA-PSO的旅行商问题TSP

目录 效果一览基本介绍建模步骤程序设计参考资料 效果一览 基本介绍 混合粒子群算法GA-PSO是一种结合了遗传算法(Genetic Algorithm, GA)和粒子群优化算法(Particle Swarm Optimization, PSO)的优化算法。在解决旅行商问题(Traveling Salesman Problem, TSP)时,这种混合算法可以结合两种算法的优点

树链剖分 + 后缀数组 - E. Misha and LCP on Tree

E. Misha and LCP on Tree  Problem's Link   Mean:  给出一棵树,每个结点上有一个字母。每个询问给出两个路径,问这两个路径的串的最长公共前缀。 analyse: 做法:树链剖分+后缀数组. 记录每条链的串,正反都需要标记,组成一个长串. 然后记录每条链对应的串在大串中的位置,对大串求后缀数组,最后询问就是在一些链

【BZOJ】1324 Exca王者之剑 最大权独立集

传送门:【BZOJ】1324  Exca王者之剑 题目分析:赤裸裸的最大权独立集。。。最小割解决 代码如下: #include <cstdio>#include <vector>#include <cstring>#include <algorithm>using namespace std ;#define REP( i , a , b ) for ( int

【HDU】5029 Relief grain 树链剖分+离线标记法

传送门:【HDU】5029 Relief grain 题目分析:这题的方法太美妙了! 首先看到这是一颗树,那么很容易想到树链剖分。然后想到可以将查询排个序,然后每一种查询执行完以后更新每个点的最优值。但是这样进行的复杂度太高!尤其是当z给的没有一样的时候尤其如此。 那么我们是否可以找到更加高效的算法? 答案是肯定的! 先简化一下问题,如果这些操作是在线段上进行的,我们怎么求解?

【BZOJ】1026: [SCOI2009]windy数 数位DP

传送门:【BZOJ】1026: [SCOI2009]windy数 题目分析:数位DP水题。 代码如下: #include <stdio.h>#include <cstring>#include <algorithm>#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )#define For( i ,

【BZOJ】2152: 聪聪可可 点分治

传送门:【BZOJ】2152: 聪聪可可 题目分析:记录权值和%3的路径的个数。。。然后去重。。没了。。 代码如下: #include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std ;typedef lo

【HDU】5221 Occupation【树链剖分】

传送门:【HDU】5221 Occupation 题目分析: 最直接的想法,用一棵树链剖分维护路径,一棵dfs序线段树维护子树。因为每次最多修改一个点,所以修改的时候我们暴力修改每个点就可以了。 my  code: my~~code: #pragma comment(linker, "/STACK:102400000,102400000")#include <stdio.h>#in

【HDU】5436 Transmigration tree【树链剖分+dp+rmq】

题目链接:【HDU】5436 Transmigration tree #pragma comment(linker, "/STACK:16777216")#include <stdio.h>#include <string.h>#include <vector>#include <algorithm>using namespace std ;typedef long long LL ;

【HDU】5566 Clarke and room【树链剖分+AC自动机】

题目链接:Clarke and room #include <bits/stdc++.h>using namespace std ;typedef long long LL ;#define ls ( o << 1 )#define lson ls , l , m#define rs ( o << 1 | 1 )#define rson rs , m + 1 , r#define rt