数列分块入门1
题目描述
给出一个长为 n的数列,以及 n个操作,操作涉及区间加法,单点查值。
第一行输入一个数字 n。
第二行输入 n个数字,第 i个数字为 ai,以空格隔开。
接下来输入 n行询问,每行输入四个数字 opt、l、r、c,以空格隔开。
若 opt=0,表示将位于 [l,r]的之间的数字都加 c。
若 opt=1,表示询问 ar的值(l和 c忽略)
Solution:
我们给每个块设置一个加法标记(就是记录这个块中元素一起加了多少),每次操作对每个整块直接O(1)标记,而不完整的块由于元素比较少,暴力修改元素的值。
每次询问时返回元素的值加上其所在块的加法标记。
#include
using namespacestd;
typedeflong longll;const int MAXN = 50000 + 10;const int M = 225;
inlineintread()
{charch;int fl=1;int x=0;do{
ch=getchar();if(ch=='-')
fl=-1;
}while(ch'9');do{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}while(ch>='0'&&ch<='9');return x*fl;
}
ll n;
ll a[MAXN];
ll opt,c,l,r;
ll now,ks;
ll add[M+10];intmain()
{
n=read();
ks=1;
now=0;for(int i=1;i<=n;i++)
{
a[i]=read();
}for(int i=1;i<=n;i++)
{
opt= read();l=read();r=read();c=read();if(opt==0)
{if((l-1)/M+1!=(r-1)/M+1)
{for(int j=l;j<=((l-1)/M+1)*M;j++) a[j]+=c;for(int j=(l-1)/M+2;j<=(r-1)/M;j++) add[j]+=c;for(int j=((r-1)/M)*M+1;j<=r;j++) a[j]+=c;
}else{for(int j=l;j<=r;j++) a[j]+=c;
}
}if(opt==1)
{
printf("%lld\n",a[r]+add[(r-1)/M+1]);
}
}
}
数列分块入门2
题目描述
给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的元素个数。
solution:
考虑把原数列分成sqrt(n)块,每块维护一个有序的序列。
首先考虑加法操作:对于整块的直接维护加法标记,不是整块的暴力修改元素,然后对块内元素重排。
然后考虑查询:对于整块的由于块内元素有序,可以直接二分。对于不是整块的暴力统计。
然而我以前写的代码WA了,加上最近没时间改,所以就不放代码了。
数列分块入门3
题目描述
给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内比某个值x其小的最大元素。
Solution:
只有查询和2不一样,那改一下二分就行了QAQ
数列分块入门4
题目描述
一个长为n的数列,以及n个操作,操作涉及区间加法,区间求和
solution:
分块后维护元素和,对于整块维护一个add标记
数列分块入门9
题目描述
给出一个长为 n的数列,以及 n个操作,操作涉及区间众数。
solution:
不会,主席树暴力拿了一个LOJ rank1,又短又好写。(现在不是了)
代码如下:
#include
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespacestd;
inlinecharnc()
{static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inlineintread()
{charch;int fl=1;int x=0;do{
ch=nc();if(ch=='-')
fl=-1;
}while(ch'9');do{
x=(x<<3)+(x<<1)+ch-'0';
ch=nc();
}while(ch>='0'&&ch<='9');return x*fl;
}const int MAXN = 100000+10;structp_tree
{intsum;intlcc;intrcc;
} ;
p_tree t[MAXN*25];int root[MAXN],cnt=0;structnode
{intval;intid;
friendbool operator
{return a1.val
}
};
node a[MAXN];intc[MAXN];intzsi,zsz;boolbz;intck;
inlinevoid update(int& rt,int x,int k,int l,intr)
{
t[++cnt]=t[rt];
rt=cnt;
t[rt].sum+=k;if(l==r) return;int mid=(l+r)>>1;if(x<=mid) update(t[rt].lcc,x,k,l,mid);else update(t[rt].rcc,x,k,mid+1,r);
}
inlinevoid query(int l,int r,int x,inty)
{if(bz) return;if(x==y)
{if(zsz
{
zsz=t[r].sum-t[l].sum;
zsi=x;
}if(zsz>(ck)/2)
{
bz= true;
}return;
}else{if(zsz
{
query(t[l].lcc,t[r].lcc,x,(x+y)>>1);
}if(zsz
{
query(t[l].rcc,t[r].rcc,((x+y)>>1)+1,y);
}
}
}intn,q;intrankk[MAXN];intmain()
{
n=read();for(register int i=1;i<=n;i++) a[i].val=read(),a[i].id=i;;
root[0]=0;
t[0].sum=t[0].lcc=t[0].rcc=0;
sort(a+1,a+n+1);int top=0;for(register int i=1;i<=n;i++)
{if(a[i].val!=a[i-1].val) top++;
c[a[i].id]=top;
rankk[top]=a[i].val;
}for(register int i=1;i<=n;i++)
{
root[i]=root[i-1];
update(root[i],c[i],1,1,100000);
}
zsi=0,zsz=0;for(register int i=1;i<=n;i++)
{
bz= false;int u=read(),v=read();if(u>v) swap(u,v);
ck= v-u+1;
zsi= 0,zsz = 0;
query(root[u-1],root[v],1,100000);
printf("%d\n",rankk[zsi]);
}
}
我暴力似乎碾标算了。。。291ms
后面的留坑