模板


题目描述:

辣鸡ljh NOI之后就退役了,然后就滚去学文化课了。

他每天都被katarina大神虐,仗着自己学过一些姿势就给katarina大神出了一道题。

有一棵 \(n\) 个节点的以 1 号节点为根的树,每个节点上有一个小桶,节点\(u\)上的小桶可以容纳\(k_{u}\)个小球,ljh每次可以给一个节点到根路径上的所有节点的小桶内放一个小球,如果这个节点的小桶满了则不能放进这个节点,在放完所有小球之后就企图去刁难katarina大神,让katarina大神回答每个节点的小桶内的小球有多少种颜色。

然而katarina大神一眼就秒掉了,还说这就是一道傻逼模板题。

现在katarina大神想考考即将参加NOIP2019的你能不能回答上辣鸡ljh的问题。

第一行,一个整数n,树上节点的数量。

接下来n ? 1行,每行两个整数u, v,表示在u, v之间有一条边。

接下来一行n个整数, ~ 表示每个节点上的小桶数量。

下一行是一个整数m,表示ljh进行的操作数量。

接下来m行,每行两个整数x, c,分别表示进行操作的节点和小球颜色。

下一行是一个整数Q,表示你需要回答的询问数。

接下来Q行,每行一个整数x,表示一个询问。


本来昨天就能A掉的,结果没考虑到负数的情况,快读直接跳过负号,

导致连WA n次的惨烈局面。(话说要是我不看测试点还要调多久啊。。。

教训:以后打快读不能偷懒为了卡一点小常数忽略负号了。

本题让我对\(splay\)的认识加深了许多。

首先是以修改时间为下标,修改时记录上每个点的时间,查询时查询时间区间就行了。

另外,对于每个点一开始都建一个\(splay\),其中包含\(root\)和一个\(map\)记录是否出现过这种小球。

当修改时先只修改最子叶的\(splay\),因为下面有着\(dfs\),可以将子树的状态合并到父节点上

至于合并的方法,是启发式合并,以前一直以为这是个什么特别厉害的东西,其实就是暴力把所有子树上的节点按照传统方式插入到父节点上...(父节点:size较大的点;

子结点:size小,插入简便的点——和\(splay\)上的父节点、子结点区分开来,这么说来,其实线段树也可以这么做吧

于是我们就可以在\(dfs\)的时候预处理出每个结点的答案,查询时直接输出即可。

\(splay\)和\(map\)的结合应用\(get\sqrt{}\)

还有,对于每个结点有一个\(rec\)数组,相当于记录了该节点在哪一颗\(splay\)树上,

在合并时如果合并到子树上就更改父亲的\(rec\),而合并到父亲上就不用更改了,因为子树的答案已经统计完了,修改\(rec\)只会浪费一点时间。

\(splay\)的中序遍历\(get\sqrt{}\)(因为左子树时间小,右子树时间大,父节点时间位于二者之间,所以按照左—父—右的顺序插入。

到这里蒟弱的思路就发表完毕了,下面是code:

Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
namespace EMT
{
#define F(i,a,b) for(register int i=a;i<=b;i++)
const int N=1e5+100;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
struct node{
int son[2],tim,size,cnt,val,fa,col;
}t[N<<2];
int head[N],co,num,ans1,rec[N],n,m,q,now;
struct edge{int next,to;}e[N<<1];
inline void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
struct tree{
map<int,int>mp;
int root;
inline int siz(){return t[root].size;}
inline int get(int x){return t[t[x].fa].son[1]==x;}
inline void up(int x){t[x].size=t[t[x].son[1]].size+t[t[x].son[0]].size+1;t[x].cnt=t[t[x].son[1]].cnt+t[t[x].son[0]].cnt+t[x].val;}
inline void res(int x){
int old=t[x].fa,oldf=t[old].fa,k=get(x);
t[old].son[k]=t[x].son[k^1];
t[t[x].son[k^1]].fa=old;
t[x].son[k^1]=old;t[old].fa=x;
if(oldf)t[oldf].son[t[oldf].son[1]==old]=x;
t[x].fa=oldf;
up(old);up(x);
}
inline void splay(int x){
for(register int fa;(fa=t[x].fa);res(x))
if(t[fa].fa)res(get(fa)==get(x)?fa:x);
root=x;
}
inline void insert(int tim,int col,int val){
int f=0,x=root;bool bg;
while((!bg)||(x&&t[x].tim!=tim))bg=1,f=x,x=t[x].son[tim>t[x].tim];
x=++num;
if(f)t[f].son[tim>t[f].tim]=x;
t[x].tim=tim;t[x].val=t[x].cnt=val;t[x].col=col;t[x].fa=f;t[x].size=1;
splay(x);
}
inline void change(int tim){
int x=root;
while(x&&t[x].tim!=tim)x=t[x].son[tim>t[x].tim];
if(x)t[x].val=0;splay(x);
}
inline int find(int tim,int col){
if(!mp[col]){
mp[col]=tim;
return 1;
}
else if(mp[col]>tim){
change(mp[col]);
mp[col]=tim;
return 1;
}
else return 0;
}
inline int findx(int x,int lim){
if(!x)return 0;
if(t[t[x].son[0]].size>=lim)findx(t[x].son[0],lim);
else if(t[t[x].son[0]].size+1>=lim)return t[t[x].son[0]].cnt+t[x].val+ans1;
else ans1+=t[t[x].son[0]].cnt+t[x].val,findx(t[x].son[1],lim-t[t[x].son[0]].size-1);
}
inline int findval(int lim){
ans1=0;
if(!lim)return 0;
if(lim>=t[root].size)return t[root].cnt;
return findx(root,lim);
}
}a[N];
inline void make(int x){
if(!x)return;
make(t[x].son[0]);
a[now].insert(t[x].tim,t[x].col,a[now].find(t[x].tim,t[x].col));
make(t[x].son[1]);
}int ans[N],k[N];
inline void dfs(int x,int fa){
for(register int i=head[x],j;i;i=e[i].next){
j=e[i].to;if(j==fa)continue;
dfs(j,x);
if(a[rec[x]].siz()<a[rec[j]].siz()){
now=rec[j];
make(a[rec[x]].root);
rec[x]=now;
}
else{
now=rec[x];
make(a[rec[j]].root);
}
}
ans[x]=a[rec[x]].findval(k[x]);
}
inline short main(){
freopen("ac7.in","r",stdin);
freopen("my.out","w",stdout);
n=read();
F(i,1,n-1){
int x=read(),y=read();add(x,y);add(y,x);
}
F(i,1,n)k[i]=read(),rec[i]=i;
m=read();
F(i,1,m){
int x=read(),y=read();
a[rec[x]].insert(i,y,a[rec[x]].find(i,y));
}
dfs(1,0);
q=read();
while(q--){
int x=read();
printf("%d\n",ans[x]);
}
return 0;
}
}
signed main() { return EMT::main();}

【模板】二逼平衡树(树套树)

链接

树套树的新题型,又让蒟弱涨见识了。

由于蒟弱在学习\(splay\),所以考虑用线段树套\(splay\)来解决本题,

对于每一个线段树结点建立一颗\(splay\)树,修改时同时修改两颗树,

当查询时利用线段树的区间性质巧妙结合二分完成查询。

另外,对于\(splay\)和线段树各建一个操作结构体,好看方便调试。

(码量有点大的说

Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
namespace EMT
{
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
#define pf printf
#define int long long
inline void s(){pf("shit\n");}
const int N=5e5+100,maxn=2147483647;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
inline void pi(int x){pf("%lld ",x);}inline void pn(){pf("\n");}inline void ps(int a[],int size){F(i,1,size)pi(a[i]);pn();}
/*------------------------------------------------------------------------Splay------------------------------------------------------------------------------------- */
struct stree{int son[2],fa,key,size,cnt;}t[N<<2];int num;
struct Splay{
int root;
inline void reset(int x,int v){t[x].son[0]=t[x].son[1]=t[x].fa=0;t[x].size=t[x].cnt=1;t[x].key=v;}
inline void clean(int x){t[x].son[0]=t[x].son[1]=t[x].fa=t[x].size=t[x].cnt=t[x].key=0;}
inline bool get(int x){return t[t[x].fa].son[1]==x;}
inline void up(int x){
if(x){
t[x].size = t[x].cnt;
t[x].size += (t[x].son[0] ? t[t[x].son[0]].size : 0) + (t[x].son[1] ? t[t[x].son[1]].size : 0);
}
}
inline void res(int x){
int old = t[x].fa, oldf = t[old].fa, which = get(x);
t[old].son[which] = t[x].son[which ^ 1];
t[t[old].son[which]].fa = old;
t[old].fa = x;
t[x].son[which ^ 1] = old;
t[x].fa = oldf;
if(oldf)t[oldf].son[t[oldf].son[1] == old] = x;
up(old);up(x);
}
inline void splay(int x){
for (int fa; (fa = t[x].fa); res(x))
if (t[fa].fa)res((get(fa) == get(x)) ? fa : x);
root = x;
}
inline void insert(int x){
if (!root){
num++;reset(num, x);root=num;return;
}
int now = root, fa = 0;
while (1){
if (t[now].key == x){
t[now].cnt++;up(now);up(fa);
splay(now);break;
}
fa = now;
now = t[now].son[t[now].key < x];
if (!now){
num++;reset(num, x);
t[num].fa = fa;t[fa].son[t[fa].key < x] = num;
up(fa);
splay(num);
break;
}
}
}
inline int pre(){
int now = t[root].son[0];
while (t[now].son[1])now = t[now].son[1];
return now;
}
inline int nxt(){
int now = t[root].son[1];
while (t[now].son[0])now = t[now].son[0];
return now;
}
inline int find(int x){
int ans = 0, now = root;
while (now){
if (x < t[now].key)
now = t[now].son[0];
else{
ans += t[now].son[0] ? t[t[now].son[0]].size : 0;
if (x == t[now].key){
splay(now);
return ans ;
}
ans += t[now].cnt;
now = t[now].son[1];
}
}return ans;
}
inline int getpre(int v){
int now=root,ans=-maxn;
while(now){
if(t[now].key<v){ans=max(ans,t[now].key),now=t[now].son[1];}
else now=t[now].son[0];
}return ans;
}
inline int getnxt(int v){
int now=root,ans=maxn;
while(now){
if(t[now].key>v){ans=min(ans,t[now].key),now=t[now].son[0];}
else now=t[now].son[1];
}return ans;
}
inline void del(int x){
find(x);
if (t[root].cnt > 1){t[root].cnt--;up(root);return;}
if (!t[root].son[0] && !t[root].son[1]){clean(root);root = 0;return;}
if (!t[root].son[0]){
int old = root;
root = t[root].son[1];
t[root].fa = 0;
clean(old);
return;
}
else if (!t[root].son[1]){
int old = root;
root = t[root].son[0];
t[root].fa = 0;
clean(old);
return;
}
int old = root, lmax = pre();
splay(lmax);
t[t[old].son[1]].fa = root;
t[root].son[1] = t[old].son[1];
clean(old);
up(root);
}
}a[N<<2];
/*-----------------------------------------------------------------------Segment-tree---------------------------------------------------------------------------------- */
int dat[N<<2],ans;
struct se{
inline void ins(int x,int l,int r,int p,int v){
a[x].insert(v);if(l==r)return;
int mid=(l+r)>>1;
if(p<=mid)ins(x*2,l,mid,p,v);
else ins(x*2+1,mid+1,r,p,v);
}
inline void change(int x,int l,int r,int p,int to){
a[x].del(dat[p]);a[x].insert(to);
if(l==r){dat[p]=to;return;}
int mid=(l+r)>>1;
if(p<=mid)change(x*2,l,mid,p,to);
else change(x*2+1,mid+1,r,p,to);
}
inline void pre(int x,int l,int r,int L,int R,int v){
if(l==L&&r==R){ans=max(ans,a[x].getpre(v));return;}
int mid=(l+r)>>1;
if(R<=mid)pre(x*2,l,mid,L,R,v);
else if(L>mid)pre(x*2+1,mid+1,r,L,R,v);
else pre(x*2,l,mid,L,mid,v),pre(x*2+1,mid+1,r,mid+1,R,v);
}
inline void nxt(int x,int l,int r,int L,int R,int v){
if(l==L&&r==R){ans=min(ans,a[x].getnxt(v));return;}
int mid=(l+r)>>1;
if(R<=mid)nxt(x*2,l,mid,L,R,v);
else if(L>mid)nxt(x*2+1,mid+1,r,L,R,v);
else nxt(x*2,l,mid,L,mid,v),nxt(x*2+1,mid+1,r,mid+1,R,v);
}
inline void rank(int x,int l,int r,int L,int R,int v){
if(l==L&&r==R){ans+=a[x].find(v);return;}int mid=(l+r)>>1;
if(R<=mid)rank(x*2,l,mid,L,R,v);
else if(L>mid)rank(x*2+1,mid+1,r,L,R,v);
else rank(x*2,l,mid,L,mid,v),rank(x*2+1,mid+1,r,mid+1,R,v);
}
}segm;
/* -------------------------------------------------------------------------ask----------------------------------------------------------------------------------------------*/
int n,m,mx;
inline int getrank(int x,int y,int k){
int l=0,r=mx,mid;
while(l<=r){
mid=(l+r)>>1;ans=0;
segm.rank(1,1,n,x,y,mid);
if(ans<k)l=mid+1;
else if(ans==k)r=mid-1;
else r=mid-1;
}return l-1;
}
inline short main(){
// freopen("in.in","r",stdin);
// freopen("my.out","w",stdout);
n=read();m=read();
F(i,1,n){dat[i]=read();segm.ins(1,1,n,i,dat[i]);mx=max(mx,dat[i]);}
F(i,1,m){
int k,op=read(),x=read(),y=read();
if(op==1){k=read();ans=0;segm.rank(1,1,n,x,y,k);pi(ans+1);pn();}
if(op==2){k=read();pi(getrank(x,y,k));pn();}
if(op==3)segm.change(1,1,n,x,y);
if(op==4){k=read();ans=-maxn;segm.pre(1,1,n,x,y,k);pi(ans);pn();}
if(op==5){k=read();ans=maxn;segm.nxt(1,1,n,x,y,k);pi(ans);pn();}
}
return 0;
}
}
signed main() { return EMT::main();}

Splay做题笔记的更多相关文章

  1. LCT做题笔记

    最近几天打算认真复习LCT,毕竟以前只会板子.正好也可以学点新的用法,这里就用来写做题笔记吧.这个分类比较混乱,主要看感觉,不一定对: 维护森林的LCT 就是最普通,最一般那种的LCT啦.这类题目往往 ...

  2. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

  3. C语言程序设计做题笔记之C语言基础知识(上)

    C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...

  4. SDOI2017 R1做题笔记

    SDOI2017 R1做题笔记 梦想还是要有的,万一哪天就做完了呢? 也就是说现在还没做完. 哈哈哈我竟然做完了-2019.3.29 20:30

  5. SDOI2014 R1做题笔记

    SDOI2014 R1做题笔记 经过很久很久的时间,shzr又做完了SDOI2014一轮的题目. 但是我不想写做题笔记(

  6. SDOI2016 R1做题笔记

    SDOI2016 R1做题笔记 经过很久很久的时间,shzr终于做完了SDOI2016一轮的题目. 其实没想到竟然是2016年的题目先做完,因为14年的六个题很早就做了四个了,但是后两个有点开不动.. ...

  7. java做题笔记

    java做题笔记 1. 初始化过程是这样的: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序 ...

  8. SAM 做题笔记(各种技巧,持续更新,SA)

    SAM 感性瞎扯. 这里是 SAM 做题笔记. 本来是在一篇随笔里面,然后 Latex 太多加载不过来就分成了两篇. 标 * 的是推荐一做的题目. trick 是我总结的技巧. I. P3804 [模 ...

  9. PKUWC/SC 做题笔记

    去年不知道干了些啥,什么省选/营题都没做. 现在赶应该还来得及(?) 「PKUWC2018」Minimax Done 2019.12.04 9:38:55 线段树合并船新玩法??? \(O(n^2)\ ...

随机推荐

  1. 一款不错的 Go Server/API boilerplate,使用 K8S+DDD+CQRS+ES+gRPC 最佳实践构建

    Golang API Starter Kit 该项目的主要目的是使用最佳实践.DDD.CQRS.ES.gRPC 提供样板项目设置. 为开发和生产环境提供 kubernetes 配置.允许与反映生产的 ...

  2. git时 Failed to connect to 127.0.0.1 port 1080: Connection refused

    在公司换了一台电脑之后发现git clone 和 npm install都失败,报错为 fatal: unable to access 'https://github.com/netease-im/N ...

  3. 2018年一名合格的web前端程序员应该会哪些技术

    有朋友让小编说一说web前端在未来几年的发展趋向,对于这个问题,恕小编无能为力,web前端技术日新月异,更新非常快,谁也不能预料未来会发生些什么 小编也只能说在2018年,react native和j ...

  4. Unittest方法 -- 测试断言

    """断言详解"""from unittest_1.it import *def add(a,b): return a - bclass B ...

  5. TCP协议的“三次握手”和“四次挥手”

    TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接.在TCP/IP协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的.三次握手的目的是同步连接双方的 ...

  6. 【洛谷1339 [USACO09OCT]】热浪Heat Wave 图论+最短路

    AC代码 #include<bits/stdc++.h> using namespace std; const int MAXN=62000+10,INF=999999; struct E ...

  7. python的web框架知识点

    一个完整的web应用:服务器收到来自浏览器的一个请求,服务器将请求内容的网页返回给浏览器,让浏览器显示出来.[而浏览器与服务器之前的传输协议是HTTP] HTTP是一个基于TCP/IP通信协议来传递数 ...

  8. pip批量安装库

    将需要安装的库名和版本号都写在一个txt文档中,每个库名占一行,例如requests==2.24.0. 然后在用pip install -r命令去找到这个txt文档批量安装里面填写的库,如果嫌速度太慢 ...

  9. Django debug page XSS漏洞(CVE-2017-12794)

    影响版本:1.11.5之前的版本 访问http://your-ip:8000/create_user/?username=<script>alert(1)</script>创建 ...

  10. centos7网卡配置文件

    HWADDR=00:0c:29:a7:8e:ee TYPE=Ethernet BOOTPROTO=staticDEFROUTE=yes PEERROUTES=yesPEERROUTES=yes IPV ...