[CSP-S模拟测试]:模板(ac)(线段树启发式合并)
题目描述
辣鸡$ljh\ NOI$之后就退役了,然后就滚去学文化课了。
他每天都被$katarina$大神虐,仗着自己学过一些姿势就给$katarina$大神出了一道题。
有一棵$n$个节点的以$1$号节点为根的树,每个节点上有一个小桶,节点$u$上的小桶可以容纳个小球,$ljh$每次可以给一个节点到根路径上的所有节点的小桶内放一个小球,如果这个节点的小桶满了则不能放进这个节点,在放完所有小球之后就企图去刁难$katarina$大神,让$katarina$大神回答每个节点的小桶内的小球有多少种颜色。
然而$katarina$大神一眼就秒掉了,还说这就是一道傻逼模板题。
现在$katarina$大神想考考即将参加$NOIP2019$的你能不能回答上辣鸡$ljh$的问题。
输入格式
第一行,一个整数$n$,树上节点的数量。
接下来$n-1$行,每行两个整数$u,v$,表示在$u,v$之间有一条边。
接下来一行$n$个整数,$k_1~k_n$表示每个节点上的小桶数量。
下一行是一个整数$m$,表示$ljh$进行的操作数量。
接下来$m$行,每行两个整数$x,c$,分别表示进行操作的节点和小球颜色。
下一行是一个整数$Q$,表示你需要回答的询问数。
接下来$Q$行,每行一个整数$x$,表示一个询问。
输出格式
对于每个询问输出一行表示这个询问的答案。
样例
样例输入1:
5
1 2
2 3
3 4
2 5
2 1 1 1 1
2
2 1
4 2
3
1
3
5
样例输出1:
2
1
0
样例输入2:
10
3 10
2 5
3 2
2 6
1 9
8 7
7 4
3 8
3 1
15 47 23 22 9 16 45 39 21 13
10
10 7
9 3
5 1
5 2
9 4
10 9
2 4
10 1
2 6
7 9
3
1
2
3
样例输出2:
7
4
6
数据范围与提示
对于$5\%$的数据,$n\leqslant 10,m\leqslant 10,k_i\leqslant 10$。
对于$30\%$的数据,$n\leqslant {10}^3,m\leqslant {10}^3,k_i\leqslant {10}^3$。
对于另外$40\%$的数据,$n\leqslant {10}^5,m\leqslant {10}^5,k_i={10}^5$。
对于$100\%$的数据,$n\leqslant {10}^5,m\leqslant {10}^5,k_i\leqslant {10}^5$。
题解
$5\%$算法:
到现在我都没想出来。
$30\%$算法:
暴力修改,$\Theta(1)$查找答案。
时间复杂度:$\Theta(n^2)$。
期望得分:$30$分。
$40\%$算法:
注意$k_i={10}^5$,也就是说,每一个桶肯定不会装超,问题也就简单了许多,转化成了[BZOJ3307]:雨天的尾巴这道题。
区别在于,这道题是维护总和,而那道题是维护最大值,而且这道题还不用LCA。
时间复杂度:$\Theta(n\log n)$。
期望得分:$40$分。
总得分:$70$分。
$100\%$算法:
对于每一个结点都用一棵线段树维护,下标为时间,存储这个时间子树中是否已经加入了小球和贡献(注意如果之前已经加入了这个小球则贡献为0)。
在线段树上二分查找答案就好了。
但是,显然这样还不够,无论是时间还是空间。
所以我们使用线段树启发式合并,利用启发式合并的方式处理出当前子树中的所有操作,同时构建出新的线段树。
我们还可以先预处理出重儿子,这样我们就可以更少的改变当前线段树里的值。
时间复杂度:$\Theta(n\log^2n)$。
期望得分:$100$分。
代码时刻
$30\%$算法:
#include<bits/stdc++.h>
using namespace std;
struct rec
{int nxt;int to;
}e[200001];
int N,M,Q;
int head[100001],cnt;
int k[100001];
int fa[100001];
bool Map[1001][1001];
int ans[100001];
void add(int x,int y)
{e[++cnt].nxt=head[x];e[cnt].to=y;head[x]=cnt;
}
void pre_dfs(int x)//预处理
{for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa[x]){fa[e[i].to]=x;pre_dfs(e[i].to);}
}
void ufs(int x,int c)//疯狂往上找,暴力修改
{while(1){if(!x)break;if(!Map[x][c]&&k[x]>0)ans[x]++;Map[x][c]=1;k[x]--;x=fa[x];}
}
int main()
{scanf("%d",&N);for(int i=1;i<N;i++){int u,v;scanf("%d%d",&u,&v);add(u,v);add(v,u);}for(int i=1;i<=N;i++)scanf("%d",&k[i]);scanf("%d",&M);if(N<=1000&&M<=1000){pre_dfs(1);while(M--){int x,c;scanf("%d%d",&x,&c);ufs(x,c);}scanf("%d",&Q);while(Q--){int x;scanf("%d",&x);printf("%d\n",ans[x]);}}return 0;
}
$40\%$算法:
#include<bits/stdc++.h>
using namespace std;
struct rec
{int nxt;int to;
}e[200001];
struct node
{int x;int c;
}q[100001];
int N,M,Q;
int head[100001],cnt;
int root[100001],trsum[10000001],ls[10000001],rs[10000001],tot;
int k[100001];
int dfsv[100001];
bool vis[100001];
int sum;
int ans[100001];
bool cmp(node a,node b){return a.c<b.c;}
void add(int x,int y)
{e[++cnt].nxt=head[x];e[cnt].to=y;head[x]=cnt;
}
void insert(int &x,int k,int l,int r)
{if(!x)x=++tot;if(l==r){trsum[x]=1;return;}int mid=(l+r)>>1;if(k<=mid)insert(ls[x],k,l,mid);else insert(rs[x],k,mid+1,r);trsum[x]=trsum[ls[x]]+trsum[rs[x]];
}
int merge(int x,int fl,int l,int r)//合并
{if(!x||!fl)return x+fl;if(l==r){trsum[x]=trsum[x]||trsum[fl];return x;}int mid=(l+r)>>1;ls[x]=merge(ls[x],ls[fl],l,mid);rs[x]=merge(rs[x],rs[fl],mid+1,r);trsum[x]=trsum[ls[x]]+trsum[rs[x]];return x;
}
void dfs(int x)
{vis[x]=1;for(int i=head[x];i;i=e[i].nxt)if(!vis[e[i].to]){dfs(e[i].to);root[x]=merge(root[x],root[e[i].to],1,M);}ans[x]=trsum[root[x]];
}
int main()
{scanf("%d",&N);for(int i=1;i<N;i++){int u,v;scanf("%d%d",&u,&v);add(u,v);add(v,u);}for(int i=1;i<=N;i++)scanf("%d",&k[i]);scanf("%d",&M);for(int i=1;i<=M;i++)scanf("%d%d",&q[i].x,&q[i].c);sort(q+1,q+M+1,cmp);for(int i=1;i<=M;i++){if(q[i].c!=q[i-1].c)sum++;//算是一个预处理吧,思路有些清奇insert(root[q[i].x],sum,1,M);}dfs(1);scanf("%d",&Q);while(Q--){int x;scanf("%d",&x);printf("%d\n",ans[x]);}return 0;
}
$100\%$算法:
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct rec
{int nxt;int to;
}e[200001];
struct node
{int x;int c;
}q[100001];
int N,M,Q;
int head[100001],cnt;
int t[100001];
map<int,int> col;//会有负的权值,所以用map
int sum;
bool vis[100001];
int son[100001];
int tr[400001],lz[400001],tle[400001],size[400001];
int ans[100001];
vector<pair<int,int> >super[100001];//用vector存储每一个点内球的颜色和时间,二维数组会MLE
void add(int x,int y)
{e[++cnt].nxt=head[x];e[cnt].to=y;head[x]=cnt;
}
void super_memset(int x)//清空
{tr[1]=size[1]=0;lz[1]=1;for(int i=0;i<super[x].size();i++)tle[super[x][i].first]=0;
}
void pushup(int x)
{tr[x]=tr[L(x)]+tr[R(x)];size[x]=size[L(x)]+size[R(x)];
}
void pushdown(int x)
{if(!lz[x])return;size[L(x)]=size[R(x)]=tr[L(x)]=tr[R(x)]=lz[x]=0;lz[L(x)]=lz[R(x)]=1;
}
void change(int x,int l,int r,int k,int v,int w)
{tr[x]+=v;size[x]+=w;if(l==r)return;pushdown(x);int mid=(l+r)>>1;if(k<=mid)change(L(x),l,mid,k,v,w);else change(R(x),mid+1,r,k,v,w);pushup(x);
}
void add(int x)
{for(int i=0;i<super[x].size();i++){pair<int,int> flag=super[x][i];if(!tle[flag.first]){change(1,1,M,flag.second,1,0);tle[flag.first]=flag.second;}else if(tle[flag.first]>flag.second){change(1,1,M,tle[flag.first],-1,0);change(1,1,M,flag.second,1,0);tle[flag.first]=flag.second;}change(1,1,M,flag.second,0,1);}
}
int ask(int x,int l,int r,int k)
{if(k<=0)return 0;if(l==r)return tr[x];pushdown(x);int mid=(l+r)>>1;if(size[L(x)]<=k)return tr[L(x)]+ask(R(x),mid+1,r,k-size[L(x)]);else return ask(L(x),l,mid,k);
}
void connect(int x,int y)
{for(int i=0;i<super[y].size();i++)super[x].push_back(super[y][i]);super[y].clear();
}
void pre_dfs(int x)
{size[x]=super[x].size();vis[x]=1;for(int i=head[x];i;i=e[i].nxt)if(!vis[e[i].to]){pre_dfs(e[i].to);size[x]+=size[e[i].to];if(size[e[i].to]>size[son[x]])son[x]=e[i].to;}
}
void pro_dfs(int x,int fa)
{for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa&&e[i].to!=son[x]){pro_dfs(e[i].to,x);super_memset(e[i].to);}if(son[x])pro_dfs(son[x],x);add(x);for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa&&e[i].to!=son[x])add(e[i].to);ans[x]=ask(1,1,M,t[x]);if(son[x]){connect(son[x],x);swap(super[x],super[son[x]]);for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa)connect(x,e[i].to);}
}
int main()
{scanf("%d",&N);for(int i=1;i<N;i++){int u,v;scanf("%d%d",&u,&v);add(u,v);add(v,u);}for(int i=1;i<=N;i++)scanf("%d",&t[i]);scanf("%d",&M);for(int i=1;i<=M;i++){scanf("%d%d",&q[i].x,&q[i].c);if(!col[q[i].c]){col[q[i].c]=++sum;q[i].c=sum;}else q[i].c=col[q[i].c];super[q[i].x].push_back(make_pair(q[i].c,i));}pre_dfs(1);memset(size,0,sizeof(size));pro_dfs(1,0);scanf("%d",&Q);while(Q--){int x;scanf("%d",&x);printf("%d\n",ans[x]);}return 0;
}
rp++
转载于:https://www.cnblogs.com/wzc521/p/11271797.html
[CSP-S模拟测试]:模板(ac)(线段树启发式合并)相关推荐
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 3850 Solved: 2061 [Submit][Sta ...
- bzoj 36733674 可持久化并查集加强版(可持久化线段树+启发式合并)
CCZ在2015年8月25日也就是初三暑假要结束的时候就已经能切这种题了%%% 学习了另一种启发式合并的方法,按秩合并,也就是按树的深度合并,实际上是和按树的大小一个道理,但是感觉(至少在这题上)更好 ...
- 线段树练习 3P3372 【模板】线段树 1
题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述 Input Description 第一行一个正整数n,接下 ...
- P3373 【模板】线段树 2
P3373 [模板]线段树 2 相对于线段树模板1有了区间乘的操作,所以增加了一个乘的延迟标记,当加和乘的次序不同的时候,我们要好好考虑这两个延迟标记对孩子的影响.所以这里我们是采取的是先乘后加. 线 ...
- P3373 【模板】线段树 2 (未完待续)
P3373 [模板]线段树 2 强烈安利这个大佬 超赞!!! 题解 本来以为这个题拿着线段树1的板子改改就好了,但是发现事情并没有那么简单,改了两天... 我们看到这个题其实涉及啦乘法和加法两种运算, ...
- [2021.1.27多校省选模拟10]跑步(线段树合并)
[2021.1.27多校省选模拟10]跑步 经典的树上启发式合并题目,维护对应子树的从当前点到子树内一个节点这个链待定,其他部分已经确定的方案数,这个东西按照对应点到根节点的路径点权和为下标存在一个权 ...
- P3372 【模板】线段树 1
P3372 [模板]线段树 1 这一题是线段树懒标记的入门,懒标记的思想就是,当查询或者更改时,需要用到某段区间,那么我们就去将需要用到的区间传递下去,否者我们不动他,像不像你不用的知识不复习,用的时 ...
- 洛谷 P3373 【模板】线段树 2 解题报告
P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上\(x\) 2.将某区间每一个数加上\(x\) 3.求出某区间每一个数的和 输入输出格式 ...
- 洛谷 P3373 【模板】线段树 2 题解
洛谷 P3373 [模板]线段树 2 题解 题面 题目链接:[戳这里](https://www.luogu.org/problemnew/show/P3373) 题目描述 输入输出格式 输入输出样例 ...
最新文章
- 9.1 正则介绍_grep(上);9.2 grep(中);9.3 grep(下)
- 算法导论水壶问题(第三版第八章思考题8-4)
- Python eval 函数 - Python零基础入门教程
- MySQL参数配置优化
- java设计智慧教室_物联网智慧教室设计方案,更便捷的智慧教学体验
- linux备份数据库软件有哪些内容,Linux网络备份MySQL数据库的应用方法
- mysql call_关于Mysql “CALL语句”
- Ubuntu批量转换图片格式
- 学校计算机管理维修制度,青岛滨海学院计算机机房管理制度
- i18n 支持参数的写法
- 装黑苹果的那些事儿(以ThinkpadE540为例)
- linux 字符 拨号上网,LINUX下用ADSL拨号上网
- AS400 资料大放送
- html5文本溢出应该怎么处理?
- mysql uuid分页优化_MySQL性能优化之分页查询优化
- 细说——sqlmap
- html表格按照编号排序,JS实现简单表格排序操作示例
- 【13】变分自编码器(VAE)的原理介绍与pytorch实现
- [OpenCV实战]10 使用Hu矩进行形状匹配
- 苯乙烯基/綦乙烯基/苯丁烯基修饰BODIPY染料|聚合物BODIPY染料定制服务