特殊做法类线段树
来源:互联网 发布:梦幻西游定心术算法 编辑:程序博客网 时间:2024/04/29 15:24
有一类神奇的线段树,我们来总结一下。。。。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------COGS 1272 AHOI 行星序列
一道看起来很简单的线段树,有两种操作,包括*k,+a,但经过思考我们发现,但操作顺序不同时(先乘后加还是先加后乘),所以我们统一为一种操作(*k => *k+0 +a => *1+a) 于是水过。。。code:
#include<iostream>#include<cstdio>#include<cstring>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,rusing namespace std;long long node[400001],a[100001];int n,p,m;long long delta[400001][2],ans;void updata(int i){node[i]=(node[i<<1]+node[i<<1|1])%p;}void build(int i,int l,int r){delta[i][0]=1;delta[i][1]=0;if (l==r) { node[i]=a[l]%p; return; }build(lch); build(rch);updata(i);}void paint(int i,int l,int r,long long k,long long a){int t;a=a%p; k=k%p; t=(r-l+1)%p; node[i]=((node[i]*k)%p+(a*t)%p)%p;delta[i][0]=(delta[i][0]*k)%p;delta[i][1]=((delta[i][1]*k)%p+a)%p;}void pushdown(int i,int l,int r){paint(lch,delta[i][0],delta[i][1]);paint(rch,delta[i][0],delta[i][1]);delta[i][0]=1; delta[i][1]=0;}void insert(int i,int l,int r,int x,int y,long long a,int kind){if (x<=l&&y>=r) { if (kind==2) paint(i,l,r,1,a); if (kind==1) paint(i,l,r,a,0); return; }pushdown(i,l,r);if (x<=mid) insert(lch,x,y,a,kind);if (y>mid) insert(rch,x,y,a,kind);updata(i);}void query(int i,int l,int r,int x,int y){if (x<=l&&y>=r) { ans=(node[i]+ans)%p;return; }pushdown(i,l,r);if (x<=mid) query(lch,x,y);if (y>mid) query(rch,x,y);}int main(){freopen("seqb.in","r",stdin);freopen("seqb.out","w",stdout);int i,kind,t,g,c;scanf("%d%d",&n,&p);for (i=1;i<=n;++i) scanf("%d",&a[i]);build(1,1,n);scanf("%d",&m);for (i=1;i<=m;++i) { scanf("%d",&kind); if (kind==1||kind==2) { c=c%p; scanf("%d%d%d",&t,&g,&c);insert(1,1,n,t,g,c,kind); } if (kind==3) { scanf("%d%d",&t,&g); ans=0; query(1,1,n,t,g); printf("%lld\n",ans); } }fclose(stdin);fclose(stdout);}
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
COGS 三元数对&&数列
统计在某数之前比某数小和某数之后比某数小(或大)的个数,思路很奇特,以数字为节点建树,然后在线单点修改,区间求值。。。
三元数对(离散化)code
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,rusing namespace std;int node[200000],n;int a[30001],b[30001];int minn[30001];int ans;long long sum;void updata(int i){node[i]=node[i<<1]+node[i<<1|1];}void insert(int i,int l,int r,int x){if (l==r&&l==x) { node[i]+=1; return; }if (x<=mid) insert(lch,x);else insert(rch,x);updata(i);}void query(int i,int l,int r,int x,int y){if (x<=l&&y>=r) { ans+=node[i];return; }if (x<=mid) query(lch,x,y);if (y>mid) query(rch,x,y);}int main(){int i,size;freopen("three.in","r",stdin);freopen("three.out","w",stdout);scanf("%d",&n);sum=0;for (i=1;i<=n;++i) { scanf("%d",&a[i]); a[i]+=2; b[i]=a[i]; }sort(b+1,b+n+1);size=unique(b+1,b+n+1)-b-1;for (i=1;i<=n;++i) a[i]=upper_bound(b+1,b+size+1,a[i])-b;size++;memset(node,0,sizeof(node));for (i=1;i<=n;++i) { insert(1,1,size,a[i]); if (i>1) { ans=0; query(1,1,size,1,a[i]-1); minn[i]=ans; } }memset(node,0,sizeof(node));for (i=n;i>=1;--i) { insert(1,1,size,a[i]); if (i<n) { ans=0; query(1,1,size,a[i]+1,size); if (i>1) sum+=ans*minn[i]; } }printf("%lld\n",sum);fclose(stdin);fclose(stdout);}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TYVJ 1728 普通平衡树
一道著名的平衡树练习题,我们考虑它的线段树做法(做死了。。。),首先离散化(为了输出原数搞一个类似映射的东西),然后以数为节点建立线段树,然后blabla乱搞就好了(蒟蒻的算法常数很大,很大) code:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define mid (l+r)/2#define lch i<<1,l,mid#define rch i<<1|1,mid+1,rusing namespace std;int node[400001],n;struct hp{int kind,x;}opt[100001];int b[100001];int f[100001],ans,rank,ansi;void updata(int i){node[i]=node[i<<1]+node[i<<1|1];}void insert(int i,int l,int r,int x,int a){if (l==r&&l==x) { node[i]+=a; return; }if (x<=mid) insert(lch,x,a);else insert(rch,x,a);updata(i);}void querynum(int i,int l,int r,int x){if (l==r&&l==x) {ansi=i; ans++; return;}if (x<=mid) querynum(lch,x);else { ans+=node[i<<1]; querynum(rch,x); }}void queryx(int i,int l,int r,int x){if (l==r&&rank<=x&&rank+node[i]>=x) { ans=l;return; } if (rank+node[i<<1]>=x) queryx(lch,x);else { rank+=node[i<<1];queryx(rch,x); } }int main(){int t,i,size;freopen("phs.in","r",stdin);freopen("phs.out","w",stdout);scanf("%d",&n);for (i=1;i<=n;++i) { scanf("%d%d",&opt[i].kind,&opt[i].x); b[i]=opt[i].x; }sort(b+1,b+n+1);size=unique(b+1,b+n+1)-b-1;for (i=1;i<=n;++i) { t=lower_bound(b+1,b+size+1,opt[i].x)-b;f[t]=opt[i].x;opt[i].x=t; }for (i=1;i<=n;++i) { if (opt[i].kind==1) insert(1,1,size,opt[i].x,1); if (opt[i].kind==2) insert(1,1,size,opt[i].x,-1); if (opt[i].kind==3) { ans=0; querynum(1,1,size,opt[i].x); printf("%d\n",ans); } if (opt[i].kind==4) { rank=0; queryx(1,1,size,f[opt[i].x]); printf("%d\n",f[ans]); } if (opt[i].kind==5) { ans=0; querynum(1,1,size,opt[i].x); rank=0; queryx(1,1,size,ans-1); printf("%d\n",f[ans]); } if (opt[i].kind==6) { ans=0; querynum(1,1,size,opt[i].x); rank=0; queryx(1,1,size,ans+node[ansi]); printf("%d\n",f[ans]); } }fclose(stdin);fclose(stdout);}-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Lcomyn
0 0
- 特殊做法类线段树
- HDU1506线段树做法
- hdu5101 线段树做法
- 【NOI2014】购票 线段树做法
- HDU1166(线段树做法)
- 【t019】window(线段树做法)
- 校门外的树线段树做法
- poj 2352 Stars (线段树做法)
- HDU2665 kth number 线段树做法
- codevs 切水果(线段树做法)
- 反转字符串 特殊做法
- 线段树的特殊运用
- 杭电1166-敌兵布阵 →线段树做法和暴力模拟做法
- 线段树求周长求交面积的做法
- JOJ 2442: Be efficient 线段树的做法
- poj 1389 Area of Simple Polygons(线段树做法)
- hdu 1166 敌兵布阵 基础线段树 2种做法
- hdu1556树状数组&&线段树2种做法
- ubuntu下软件安装方法
- 怎么用java把 To be or not to be变成eb ot ton ro eb oT
- SQLite的查询优化
- 开源项目汇总
- 学习(4)
- 特殊做法类线段树
- 教程:Ubuntu 14.04 和 Windows 8.1 双系统安装步骤
- ant android crunch 打包报错
- Servlet 入门
- linux下使用C或C++实现进程管理代码
- 第16周oj项目-1
- 控制文件恢复系列(2)
- The art of counting in fpga
- NSTimer不会被释放