[NOIP10.6模拟赛]2.equation题解--DFS序+线段树
题目链接:
咕
闲扯:
终于在集训中敲出正解(虽然与正解不完全相同),开心QAQ
首先比较巧,这题是\(Ebola\)出的一场模拟赛的一道题的树上强化版,当时还口胡出了那题的题解
然而考场上只得了86最后一个substask被卡了,一开始以为毒瘤出题人卡常(虽然真卡了)卡线段树,题目时限1.5s,评测机上两个点擦线1500ms左右,剩下两个点不知道。然后本地测一下都是1900+ms!机子性能已经这样了吗....结果把快读换成\(fread\),TM过了!最慢的1200+ms!!!这......无话可说,\(getchar()\)快读也卡讲究
分析:
首先最简单的处理不讲了.就是把每个点的未知数表示成\(k_i x_1 + b_i\)的形式,这DFS一遍就好了
然后观察到有一个1e3的子任务,想想暴力怎么做,我们对于操作1,相当于\((k_i+k_j)x_1+(b_i+b_j)=w\)判断一下解得情况就好了,\(O(1)\)完成;
对于操作2,我们可以发现对于\(x\)的操作,只会对\(x\)的子树中的\(k_ix_1+b_i\)形式有影响(实际上只会影响\(b_i\)),于是\(DFS\)一遍子树即可,这样总的暴力时间复杂度是\(O(nq)\)
考虑优化暴力,
我们发现瓶颈是操作2,如果将\(x\)与其父亲的边权从\(w_1\)改为\(w_2\),那么加入\(x\)本来形式是\(k_ix_1+b_i\),这时候变成了\(k_i x_1+b_i+w_2-w_1\),相当于加操作,当时在\(x\)的子树中与\(x\)的\(k_i\)(实际上显然只有-1,1两种取值)不同的点,\(b\)值却应该减去\(w_2-w_1\),所以我们将标记开成一个二元组,一个记录标记的正负,另一个记录值,重载下运算符就很方便了
struct Tag{
int o;//标记的正负
ll dt;
Tag(){o=dt=0;}
Tag(int o){o=dt=o;}
Tag(int _o,ll _dt){o=_o,dt=_dt;}
Tag operator +(const Tag &b)const{
Tag tmp=*this;
if(tmp.o==0)tmp=b;
else if(b.o==0)return tmp;
else {
if(o!=b.o){
tmp.dt=dt-b.dt;
}
else tmp.dt=dt+b.dt;
}
return tmp;
}
};
这样对于操作2,只用在子树加个标记就好了,因为dfs序是一段连续区间(我比较傻考场上是用树链剖分)使用线段树就好了
对于操作1,我们两次单点查询就好了,然后按暴力那样处理.
总的时间复杂度\(O(q log N)\),常数稍大
当然标算std是将深度分奇偶考虑,然后树状数组维护差分标记,时间复杂度相同但是常数小的多
代码
这是考场代码换了快读,如果想看线段树部分直接跳到\(niconicoi\)那个\(namespace\)就好了
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
#include <cmath>
#include <vector>
#define ll long long
#define ri register int
using std::min;
using std::abs;
using std::max;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=nc()))ne=c=='-';
x=c-48;
while(isdigit(c=nc()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
const int maxn=100005;
const int inf=0x7fffffff;
const int N=1000005;
struct Edge{
int ne,to;
ll dis;
}edge[N<<1];
int h[N],num_edge=1;
inline void add_edge(int f,int to,int c){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
edge[num_edge].dis=c;
h[f]=num_edge;
}
struct Wt{
int ki;
ll bi;
Wt(){ki=bi=0;}
Wt(int _k,ll _b){ki=_k,bi=_b;}
}pt[N];
int n,q;
int fafa[N],fa_id[N];
namespace wtf{
void main(){
/*orz*/
return ;
}
}
void pre_dfs(int now,int fa){
int v;
int x=pt[now].ki,y=pt[now].bi;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa)continue;
fafa[v]=now;
fa_id[v]=i;
pt[v]=Wt(-x,edge[i].dis-y);
pre_dfs(v,now);
}
return;
}
namespace qwq{
void main(){
int op,x,y;ll dd;
ll p=edge[2].dis;
while(q--){
read(op),read(x),read(y);
if(op==1){
read(dd);
if(x!=y){
if(dd==p){
puts("inf");
}
else{
puts("none");
}
}
else {
if(x==1){
if(dd%2)puts("none");
else printf("%lld\n",dd/2);
}
if(x==2){
ll tt=2*p-dd;
if(tt%2)puts("none");
else printf("%lld\n",tt/2);
}
}
}
else{
p=y;
}
}
return ;
}
}
namespace task_1{
void main(){
int op,x,y;ll dd;
int kk,bb;
while(q--){
read(op),read(x),read(y);
if(op==1){
read(dd);
kk=pt[x].ki+pt[y].ki;
bb=pt[x].bi+pt[y].bi;
dd=dd-bb;
if(kk==0){
if(dd==0)puts("inf");
else puts("none");
}
else if(dd%abs(kk)!=0)puts("none");
else printf("%lld\n",dd/kk);
}
else {
edge[fa_id[x]].dis=y;
edge[fa_id[x]^1].dis=y;
pre_dfs(fafa[x],fafa[fafa[x]]);
}
}
return ;
}
}
namespace niconiconi{
int dep[N],top[N],son[N],size[N],dfn[N],rnk[N],tot=0;
void print(ll xxx){
if(!xxx)return ;
print(xxx/10);
putchar(xxx%10+'0');
return ;
}
void dfs_1(int now){
int v;size[now]=1;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fafa[now])continue;
dep[v]=dep[now]+1;
dfs_1(v);
size[now]+=size[v];
if(!son[now]||size[son[now]]<size[v])son[now]=v;
}
return ;
}
void dfs_2(int now,int t){
int v;top[now]=t;
dfn[now]=++tot,rnk[tot]=now;
if(!son[now])return ;
dfs_2(son[now],t);
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fafa[now]||v==son[now])continue;
dfs_2(v,v);
}
return ;
}
struct Tag{
int o;//标记的正负
ll dt;
Tag(){o=dt=0;}
Tag(int o){o=dt=o;}
Tag(int _o,ll _dt){o=_o,dt=_dt;}
Tag operator +(const Tag &b)const{
Tag tmp=*this;
if(tmp.o==0)tmp=b;
else if(b.o==0)return tmp;
else {
if(o!=b.o){
tmp.dt=dt-b.dt;
}
else tmp.dt=dt+b.dt;
}
return tmp;
}
};
Tag tag[N<<2];
void build(int now,int l,int r){
tag[now]=Tag(0);
if(l==r){
return ;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
return ;
}
int L,R;
Tag dta;
inline void pushdown(int now){
if(tag[now].o==0)return ;
tag[now<<1]=tag[now<<1]+tag[now];
tag[now<<1|1]=tag[now<<1|1]+tag[now];
tag[now]=Tag(0);
return ;
}
void update(int now,int l,int r){
if(L<=l&&r<=R){
tag[now]=tag[now]+dta;
return ;
}
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid)update(now<<1,l,mid);
if(mid<R)update(now<<1|1,mid+1,r);
return ;
}
Wt pa,pb;
int t;
void query(int now,int l,int r){
if(l==r){
//int kkk=pt[rnk[l]].ki,bbb=pt[rnk[l]].bi;
if(tag[now].o!=0){
if(tag[now].o!=pt[rnk[l]].ki){
pt[rnk[l]].bi-=tag[now].dt;
}
else{
pt[rnk[l]].bi+=tag[now].dt;
}
tag[now]=Tag(0);
}
//pa.ki=pt[rnk[l]].ki;
//pa.bi=pt[rnk[l]].bi;
return;
}
int mid=(l+r)>>1;
pushdown(now);
if(t<=mid)query(now<<1,l,mid);
else query(now<<1|1,mid+1,r);
return ;
}
void main(){
int op,x,y;
ll kk,bb,dd;
dep[1]=0;
dfs_1(1);
dfs_2(1,1);
build(1,1,n);
while(q--){
read(op),read(x),read(y);
if(op==1){
read(dd);
t=dfn[x];//pa=Wt(0,0);
query(1,1,n);
t=dfn[y];//pb=Wt(pa.ki,pa.bi),pa=Wt(0,0);
query(1,1,n);
//printf("%d %d %d %d\n",pa.ki,pb.ki,pa.bi,pb.bi);
kk=pt[x].ki+pt[y].ki;
bb=pt[x].bi+pt[y].bi;
dd=dd-bb;
if(kk==0){
if(dd==0)puts("inf");
else puts("none");
}
else if(dd%abs(kk)!=0)puts("none");
else {
if(dd==0)puts("0");
else {
dd=dd/kk;
if(dd<0)dd=-dd,putchar('-');
print(dd);
puts("");
}
//printf("%lld\n",dd/kk);
}
}
else {
dd=edge[fa_id[x]].dis;
edge[fa_id[x]].dis=edge[fa_id[x]^1].dis=y;
dd=1ll*y-dd;
//printf("%lld\n",dd);
L=dfn[x],R=dfn[x]+size[x]-1;
//t=dfn[x];pa=Wt(0,0);
//query(1,1,n);
pa=pt[x];
//printf("%d\n",pa.ki);
dta=Tag(pa.ki,dd);
update(1,1,n);
//update_subtree()
}
}
return ;
}
}
int main(){
int x,y;
freopen("equation.in","r",stdin);
freopen("equation.out","w",stdout);
read(n),read(q);
for(ri i=2;i<=n;i++){
read(x),read(y);
add_edge(i,x,y);
add_edge(x,i,y);
}
pt[1].ki=1,pt[1].bi=0;
fafa[1]=0;
pre_dfs(1,0);
if(q==0)wtf::main();
else if(n==2)qwq::main();
else if(n<=2000)task_1::main();
else niconiconi::main();
fclose(stdin);
fclose(stdout);
return 0;
}
[NOIP10.6模拟赛]2.equation题解--DFS序+线段树的更多相关文章
- BZOJ 3252题解(贪心+dfs序+线段树)
题面 传送门 分析 此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做 这里给出DFS序+线段树的代码 我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x 每次从根 ...
- 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树
题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...
- BZOJ1103 [POI2007]大都市meg dfs序 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1103 题意概括 一棵树上,一开始所有的边权值为1,我们要支持两种操作: 1. 修改某一条边的权值为 ...
- CodeForces 877E Danil and a Part-time Job(dfs序+线段树)
Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...
- 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...
- CodeForces 877E DFS序+线段树
CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...
- [51nod 1681]公共祖先(dfs序+线段树合并)
[51nod 1681]公共祖先(dfs序+线段树合并) 题面 给出两棵n(n<=100000)个点的树,对于所有点对求它们在两棵树中公共的公共祖先数量之和. 如图,对于点对(2,4),它们在第 ...
- 牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树)
牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树) 链接:https://ac.nowcoder.com/acm/problem/15706 现在需要您来帮忙维护这个名册, ...
- codevs1228 (dfs序+线段树)
1228 苹果树 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结 ...
随机推荐
- web前端——Vue.js基础学习之class与样式绑定
打着巩固 css 知识的旗号开始了对 vue 样式绑定的研究,相比前一篇的 demo,本次内容多了各种样式在里面,变得稍微花哨了些,话不多说,直接上代码吧: <html> <head ...
- SQL-W3School-基础:SQL SELECT 语句
ylbtech-SQL-W3School-基础:SQL SELECT 语句 1.返回顶部 1. 本章讲解 SELECT 和 SELECT * 语句. SQL SELECT 语句 SELECT 语句用于 ...
- 手把手教你实现RecyclerView的下拉刷新和上拉加载更多
手把手教你实现RecyclerView的下拉刷新和上拉加载更多 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https:// ...
- [Java复习] Spring 常见面试问题
1. 什么是 Spring 框架?Spring 框架有哪些主要模块? 轻量级实现IoC和AOP的JavaEE框架. Core模块: bean(bean定义创建解析), context(环境, IoC容 ...
- PS改变图片像素大小(一寸照片变二寸)
1.打开Photoshop,点击“文件”菜单,选择“打开”,将要处理的图片加载进来 2.找到“图像”菜单,选择“图像大小”,我们在这里对图片进行处理. 3.根据需要对其分辨率或者尺寸进行设置,设置好后 ...
- 自己写了个简单的redis分布式锁【我】
自己写了个简单的redis分布式锁 [注意:此锁需要在每次使用前都创建对象,也就是要在线程内每次都创建对象后使用] package redis; import java.util.Collection ...
- Python xlwt 模块执行出错Exception: String longer than 32767 characters
使用Python搜集数据时用到xlwt保存到excel文件,但是数据量有点大时出现 Exception: String longer than 32767 characters 搜索类似的问题都是建议 ...
- 关于Android Studio中Gradle的一些乱七八糟的问题
版本下载:https://gradle.org/releases/ 一个很详细的blog说明文:https://www.cnblogs.com/smyhvae/p/4390905.html,不贴具体内 ...
- React Native使用NetInfo对当前系统网络的判断
有网状态: 断网状态: 代码如下: 注意:第一次参考了http://www.hangge.com/blog/cache/detail_1614.html代码,一直显示的是unknow状态... 最后处 ...
- 【ARTS】01_28_左耳听风-201900520~201900526
ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...