关闭输入输出流同步(调试时注释掉)
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
输入优化 //read(n);
template<class T>inline void read(T &x){x=0;int f=0;char ch=getchar();while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}x=f?-x:x;return;}
输出优化 //write(n);
template<class T>inline void write(T x){if(x<0){putchar('-'); x=-x;}if(x>9) write(x/10);putchar(x%10+'0');}
赋值 strcpy(s1,s2);
长度 strlen(s);
比较 strcmp(s1,s2);
连接 strcat(s1,s2);
查找字串 strstr(s1,s2); //返回s2在s1中的位置,找不到则返回NULL
<,>, ==号都已重载,可以直接使用(字典序)
添加 s+='a';
长度 s.length();
详解传送门
例题点这儿
例题 我的代码
#include
#include
#include
#include
using namespace std;
#define ll long long
#define M 81000
struct node{
int v,x;
}t[M];
int a[M],n,cnt,pre[M],now;
ll ans;
int main(){
// freopen("now.in","r",stdin);
cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
t[++cnt].v=a[1];t[cnt].x=1;pre[1]=cnt;
int i=2;now=1;
while(i<=n){
while(a[i]>=t[cnt].v&&cnt>=1){
ans+=now-pre[t[cnt].x];
cnt--;
}
t[++cnt].v=a[i];
pre[i]=++now;
t[cnt].x=i++;
}
while(cnt){
ans+=now-pre[t[cnt--].x];
}
cout<<ans;
// fclose(stdin);
}
详解传送门
例题1点这儿
例题2点这儿,代码有注释
例题1 我的代码
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define M 1010000
struct node{
int v,id;
}q[M];
int h,t,n,k,a[M],ans[M],cnt;
int main(){
// freopen("testdata.in","r",stdin);
cin>>n>>k;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
h=1;t=0; //小
for(int i=1;i<=n;i++){
while(h<=t&&i-q[h].id+1>k)h++;
while(h<=t&&a[i]<=q[h].v)h++;
while(h<=t&&a[i]<=q[t].v)t--;
q[++t].v=a[i];q[t].id=i;
if(i>=k)ans[++cnt]=q[h].v;
}
for(int i=1;i<=cnt;i++)cout<<ans[i]<<" ";cout<<endl;
h=1;t=0;cnt=0; //大
for(int i=1;i<=n;i++){
while(i-q[h].id+1>k)h++;
while(h<=t&&a[i]>=q[h].v)h++;
while(h<=t&&a[i]>=q[t].v)t--;
q[++t].v=a[i];q[t].id=i;
if(i>=k)ans[++cnt]=q[h].v;
}
for(int i=1;i<=cnt;i++)cout<<ans[i]<<" ";
// fclose(stdin);
}
例题2 我的代码
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define M 2010000
int h,t,k,all;
struct node{
int v,id;
}q[M];
int main(){
// freopen("now.in","r",stdin);
cin>>all;
char c[10];
int x;
while(all--){ //多组数据
h=1;t=0;k=0;int now=0; //h队首,t队尾,k前面结束面试的人数,now面试人数统计
while(scanf("%s",c),c[0]!='E'){ //E为END
if(c[0]=='S')continue;else //S为START
if(c[0]=='C'){ //C为加入一个来面试的人
scanf("%s%d",c,&x);
now++; //计数器+1
while(h<=t&&q[h].v<=x)h++; //队首可维护性比x低的出队
while(h<=t&&q[t].v<=x)t--; //队尾可维护性比x低的出队
q[++t].v=x;q[t].id=now; // x入队,id记录入队的次序
}else
if(c[0]=='G'){ //G尾排在前面的人结束面试离开
if(k<now)k++; //计数
while(h<=t&&q[h].id<=k)h++;//如果队首入队的次序小于等于k,那么他就是结束面试离开了
}else
if(c[0]=='Q'){ //Q为询问最大
if(h<=t)printf("%d\n",q[h]);//队列不为空
else printf("-1\n"); //队列为空
}else continue;
}
}
// fclose(stdin);
}
include<queue>
include<vector>
①大根堆
priority_queue<int>h; //默认大根堆
②小根堆
priority_queue<int,vector<int>,greater<int> >h;
③附加信息大根堆
#include
priority_queue<pair<int,node>,vector<pair<int node> > >h;
入堆
int a;node b;
h.push(make_pair(a,b));
出堆
pair<int,node>a;
a=h.top();h.pop();
调用时用a.first和a.second
empty() 如果队列为空,则返回真
pop() 删除对顶元素,删除第一个元素
push() 加入一个元素
size() 返回优先队列中拥有的元素个数
top() 返回优先队列对顶元素,返回优先队列中有最高优先级的元素
struct cmp {
operator bool ()(int x, int y)
{
return x > y; // x小的优先级高
//也可以写成其他方式,如: return p[x] > p[y];表示p[i]小的优先级高
}
};
priority_queue<int, vector<int>, cmp> q; //定义方法
//其中,第二个参数为容器类型。第三个参数为比较函数。
3、结构体声明方式: ★★★自定义优先级用这个!
struct node {
int x, y;
friend bool operator < (node a, node b)
{
return a.x > b.x; //结构体中,x小的优先级高
}
};
priority_queue<node>q; //定义方法
//在该结构中,y为值, x为优先级。
//通过自定义operator<操作符来比较元素中的优先级。
//在重载”<”时,最好不要重载”>”,可能会发生编译错误
#include //小根堆
using namespace std;
int heap[20050],cur; //cur堆中元素数
void insert(int val){} //插入
heap[++cur]=val;
int t=cur;
while(t>1){} //新元素没成为树根时
int root=t/2; //找爸爸
if(heap[root]>val)swap(heap[root],heap[t]); //交换
else break;
t=root; //变成爸爸
}
}
int pop(){ //删除(取数)
if(cur==0)return -1;
int t=heap[1]; //保存根顶
heap[1]=heap[cur--];
int root=1;
while(2*root<=cur){} //还没变成树叶
int l=root*2,r=root*2+1; //左右儿子
if(r>cur||heap[l]<heap[r])
if(heap[root]>heap[l]{
swap(heap[root],heap[l]);
root=l;
}else break;
else
if(heap[root]>heap[r]){
swap(heap[root],heap[r]);
root=r;
}else break;
}
return t;
}
静态RMQ,Onlogn建表,O1查询
const int N=100007;
int a[N],st[N][20];
void st_init(){//初始化
for(int i=1;i<=n;i++)st[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int st_query(int l,int r){//查询
int k=log2(r-l+1);
return max(st[l][k],st[r-(1<<k)+1][k]);
}
相对于线段树的优点:省空间,常数小,速度快
—维护前缀和
—单点修改,区间求和
—区间修改(维护差分数组前缀和)+单点查询
—可以解决逆序对
int n;
int a[1005],c[1005]; //对应原数组和树状数组
int lowbit(int x){ // 找x二进制最低位的1对应的值
return x&(-x);
}
void updata(int i,int k){ //在i位置加上k
while(i <= n){
c[i] += k;
i += lowbit(i);
}
}
int getsum(int i){ //求A[1 - i]的和
int ans = 0;
while(i > 0){
ans += c[i];
i -= lowbit(i);
}
return ans;
}
—单点修改、区间修改、区间查询
模板题传送门
涉及操作:1.区间修改,把区间每个数修改为val
(3.单点修改(可以套区间修改的函数modify(p,p,1,n,1,val))
3.区间求和
#define ll long long
#define M 101000
int t[M*4],lazy[M*4],n;//存树和lazy的数组要开4倍的MAXN
void push_up(int k){ //状态往上更新合并
t[k]=t[k<<1]+t[k<<1|1];
}
void push_down(int k,int l,int r){ //下放lazy标记
if(lazy[k]==0)return;
int m=(l+r)>>1;
lazy[k<<1]=lazy[k<<1|1]=lazy[k];
t[k<<1]=(m-l+1)*lazy[k];
t[k<<1|1]=(r-m)*lazy[k];
lazy[k]=0;
}
void build(int l,int r,int k){ //建树
if(l==r){
t[k]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
push_up(k);
}
void updata(int p,int l,int r,int k,int val){ //单点修改(+、-)
if(l==r){
tr[k]+=val;
return;
}
int mid=(l+r)>>1;
if(p<=mid)updata(p,l,mid,k<<1,val);
else updata(p,mid+1,r,k<<1|1,val);
push_up(k);
}
void modify(int l_,int r_,int l,int r,int k,int val){ //区间修改(+、-)
if(l_<=l&&r_>=r){
lazy[k]=val;
t[k]=(r-l+1)*val;
return;
}
int mid=(l+r)>>1;
push_down(k,l,r);
if(l_<=mid)modify(l_,r_,l,mid,k<<1,val);
if(r_>mid)modify(l_,r_,mid+1,r,k<<1|1,val);
push_up(k);
}
int query(int l_,int r_,int l,int r,int k){ //区间查询
if(l_<=l&&r_>=r)return t[k];
int mid=(l+r)>>1;
push_down(k,l,r);
int s=0;
if(l_<=mid)s+=query(l_,r_,l,mid,k<<1);
if(r_>mid)s+=query(l_,r_,mid+1,r,k<<1|1);
return s;
}
----区间加减+区间乘法+区间求和
模板题传送门
涉及操作:1.区间乘法,把区间每个数乘val
2.区间加减,把区间每个数加减val
3.区间求和
思路,开两个lazy数组,打乘法标记时,把当前点的加法标记也乘上val。push_down操作时先乘后加即可(因为加法是已经乘上了乘法标记的)
#include
using namespace std;
#define MAXN 100007
#define ll long long
ll n,m,a[MAXN];
ll t[MAXN*4],lazy[MAXN*4],p,lazy2[MAXN*4];//lazy是加法懒标记,lazy2是乘法懒标记
template<class T>void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
} //快读
void push_up(int k){
t[k]=(t[k<<1]+t[k<<1|1])%p;
} 向上更新区间和
void push_plus(int k,int l,int r){
if(l==r||lazy[k]==0)return;
lazy[k<<1]=(lazy[k<<1]+lazy[k])%p;
lazy[k<<1|1]=(lazy[k<<1|1]+lazy[k])%p;
int md=(l+r)>>1;
t[k<<1]=(t[k<<1]+lazy[k]*(md-l+1)%p)%p;
t[k<<1|1]=(t[k<<1|1]+lazy[k]*(r-md)%p)%p;
lazy[k]=0;
}//下放加法懒标记
void push_multi(int k,int l,int r){
if(l==r||lazy2[k]==1)return;
lazy[k<<1]=lazy[k<<1]*lazy2[k]%p;
lazy[k<<1|1]=lazy[k<<1|1]*lazy2[k]%p;
lazy2[k<<1]=lazy2[k<<1]*lazy2[k]%p;
lazy2[k<<1|1]=lazy2[k<<1|1]*lazy2[k]%p;
int md=(l+r)>>1;
t[k<<1]=t[k<<1]*lazy2[k]%p;
t[k<<1|1]=t[k<<1|1]*lazy2[k]%p;
lazy2[k]=1;
}//下放乘法懒标记(对应点的加法懒标记同时也乘上val)
void build(int l,int r,int k){
if(l==r){
t[k]=a[l]%p;
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
push_up(k);
}//建树
void updata_plus(int l_,int r_,int l,int r,int k,int val){
if(l_<=l&&r_>=r){
lazy[k]=(lazy[k]+val)%p;
t[k]=(t[k]+(r-l+1)*val%p)%p;
return;
}
int mid=(l+r)>>1;
push_multi(k,l,r);
push_plus(k,l,r);//先乘后加
if(l_<=mid)updata_plus(l_,r_,l,mid,k<<1,val);
if(r_>mid)updata_plus(l_,r_,mid+1,r,k<<1|1,val);
push_up(k);
}//区间加减
void updata_multi(int l_,int r_,int l,int r,int k,int val){
if(l_<=l&&r_>=r){
lazy[k]=lazy[k]*val%p;//加法标记同时也乘val
lazy2[k]=lazy2[k]*val%p;
t[k]=t[k]*val%p;
return;
}
int mid=(l+r)>>1;
push_multi(k,l,r);
push_plus(k,l,r);
if(l_<=mid)updata_multi(l_,r_,l,mid,k<<1,val);
if(r_>mid)updata_multi(l_,r_,mid+1,r,k<<1|1,val);
push_up(k);
}//区间乘法
ll query(int l_,int r_,int l,int r,int k){
if(l_<=l&&r_>=r)return t[k]%p;
int mid=(l+r)>>1;
ll sum=0;
push_multi(k,l,r);
push_plus(k,l,r);
if(l_<=mid)sum=(sum+query(l_,r_,l,mid,k<<1))%p;
if(r_>mid)sum=(sum+query(l_,r_,mid+1,r,k<<1|1))%p;
return sum;
}
int main(){
cin>>n>>m>>p;
for(int i=1;i<=n;i++)read(a[i]);
for(int i=1;i<=MAXN*4-1;i++)lazy2[i]=1;
build(1,n,1);
int b,c,d,e;
for(int i=1;i<=m;i++){
read(b);
if(b==1){//乘法
read(c);read(d);read(e);
updata_multi(c,d,1,n,1,e);
}else
if(b==2){//加法
read(c);read(d);read(e);
updata_plus(c,d,1,n,1,e);
}else{//求和
read(c);read(d);
printf("%lld\n",query(c,d,1,n,1));
}
}
}
xjb更新,xjb查询就用分块 Ovo , 时间复杂度是加一个√n
!丧心病狂的出题人可能会卡√n ,这时候可以用√n +1或√n -1或√(n/lgn)
Loj分块入门1~9题传送门
上题hzwer学长的详解链接、我的题解链接
模板涉及操作: 1.单点加减
2.区间加减
3.区间求和
#define maxn 500007
typedef long long ll;
int n,m,size,cnt,l[maxn],r[maxn],belong[maxn];
ll v[maxn],a[maxn],lazy[maxn];
//l,r是第i块的左右端点,belong记录i点属于哪个块
//size是块的大小,cnt是块的数量,v是块维护的值
void build(){ //划分建块
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;//设定块的大小和数量
for(int i=1;i<=cnt;i++) //记录每个块的左右端点
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++) //记录每个点属于哪个块
belong[i]=(i-1)/size+1;
for(int i=1;i<=cnt;i++) //初始化
for(int j=l[i];j<=r[i];j++)
v[i]+=a[j];
}
inline void plus(int x,int val){//单点加val
a[x]+=val;
v[belong[x]]+=val;
}
inline void add(int L,int R,ll c){//区间加val
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)a[i]+=c,v[belong[i]]+=c;
return;
}
for(int i=L;i<=r[belong[L]];i++)a[i]+=c,v[belong[i]]+=c;
for(int i=belong[L]+1;i<belong[R];i++)lazy[i]+=c;
for(int i=l[belong[R]];i<=R;i++)a[i]+=c,v[belong[i]]+=c;
}
inline ll query(int L,int R,ll c){//区间求和(mod c)
ll ans=0;
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)ans=(ans+a[i]+lazy[belong[i]])%c;
return ans;
}
for(int i=L;i<=r[belong[L]];i++)ans=(ans+a[i]+lazy[belong[i]])%c;
for(int i=belong[L]+1;i<belong[R];i++)ans=(ans+v[i]+lazy[i]*(r[i]-l[i]+1))%c;
for(int i=l[belong[R]];i<=R;i++)ans=(ans+a[i]+lazy[belong[i]])%c;
return ans;
}
//inline ll query_(int l_,int r_){//没有lazy数组的区间求和
// ll ans=0;
// if(belong[l_]==belong[r_]){//在同一个块内
// for(int i=l_;i<=r_;i++)ans+=a[i];
// return ans;
// }
// for(int i=l_;i<=r[belong[l_]];i++)
// ans+=a[i]; //左端点非整体块暴力
// for(int i=belong[l_]+1;i
// ans+=v[i]; //中间整体快累加
// for(int i=l[belong[r_]];i<=r_;i++)
// ans+=a[i]; //右端点非整体块暴力
// return ans;
//}
分块练习2,涉及操作:区间加减,求区间内小于k的元素个数。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=50007;
template<class T>inline void read(T &x){
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int n,size,cnt,l[N],r[N],belong[N];
int a[N],lazy[N];
vector<int>vec[505];//块内排序
void build(){
size=sqrt(n);
cnt=n/size;if(n%size)cnt++;
for(int i=1;i<=cnt;i++)
l[i]=(i-1)*size+1,r[i]=i*size;
r[cnt]=n;
for(int i=1;i<=n;i++){
belong[i]=(i-1)/size+1;
vec[belong[i]].push_back(a[i]);
}
for(int i=1;i<=cnt;i++)
sort(vec[i].begin(),vec[i].end());
}
void reset(int x){//重新排序
vec[x].clear();
for(int i=l[x];i<=r[x];i++)
vec[x].push_back(a[i]);
sort(vec[x].begin(),vec[x].end());
}
void add(int L,int R,int c){
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)a[i]+=c;
reset(belong[L]);
return;
}
for(int i=L;i<=r[belong[L]];i++)a[i]+=c;
reset(belong[L]);
for(int i=belong[L]+1;i<belong[R];i++)lazy[i]+=c;
for(int i=l[belong[R]];i<=R;i++)a[i]+=c;
reset(belong[R]);
}
int query(int L,int R,int c){
int ans=0;
if(belong[L]==belong[R]){
for(int i=L;i<=R;i++)
if(a[i]+lazy[belong[i]]<c)ans++;
return ans;
}
for(int i=L;i<=r[belong[L]];i++)
if(a[i]+lazy[belong[i]]<c)ans++;
for(int i=belong[L]+1;i<belong[R];i++){
int x=c-lazy[i];
ans+=lower_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin();
}
for(int i=l[belong[R]];i<=R;i++)
if(a[i]+lazy[belong[i]]<c)ans++;
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)read(a[i]);
build();
int opt,l,r,c;
for(int i=1;i<=n;i++){
read(opt);read(l);read(r);read(c);
if(opt==0)add(l,r,c);
else printf("%d\n",query(l,r,c*c));
}
}
操作随机的话复杂度接近O(mlogn)
!1.必须先split(r+1),再split(l),否则可能会使split(l)的迭代器失效
__2.初始化插入完节点后,要插入一个node(n+1,n+1,0)的节点
----> 例题1(生成随机数)传送门
----> 题解1传送门
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
#define IT set::iterator
const int MAXN=1e5+7;
const int MOD7=1e9+7;
struct node{
int l,r;
mutable LL v;
node(int L,int R=-1,LL V=0):l(L),r(R),v(V){}
bool operator<(const node &o)const{
return l<o.l;
}
};
LL qpow(LL a,LL b,LL mod){//快速幂
LL ans=1;
LL x=a%mod;
while(b){
if(b&1)ans=ans*x%mod;
x=x*x%mod;
b>>=1;
}
return ans;
}
set<node>s;
IT split(int pos){//必须先split(r+1),再split(l)
IT it=s.lower_bound(node(pos));
if(it!=s.end()&&it->l==pos)return it;
--it;
int L=it->l,R=it->r;
LL V=it->v;
s.erase(it);
s.insert(node(L,pos-1,V));
return s.insert(node(pos,R,V)).first;
}
void add(int l,int r,LL val){//给l到r所有数加上val
IT itr=split(r+1),itl=split(l);
for(;itl!=itr;++itl)
itl->v+=val;
}
void assign_val(int l,int r,LL val){//把l到r所有数改为val
IT itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert(node(l,r,val));
}
LL ranks(int l,int r,int k){//询问l到r区间第k小
vector<pair<LL,int> >vp;
IT itr=split(r+1),itl=split(l);
vp.clear();
for(;itl!=itr;++itl)
vp.push_back(pair<LL,int>(itl->v,itl->r - itl->l +1));
sort(vp.begin(),vp.end());
for(vector<pair<LL,int> >::iterator it=vp.begin();it!=vp.end();++it){
k-=it->second;
if(k<=0)return it->first;
}
}
LL sum(int l,int r,int ex,int mod){//询问l到r每个数字的x次方模y的和
IT itr=split(r+1),itl=split(l);
LL res=0;
for(;itl!=itr;++itl)
res=(res+(LL)(itl->r - itl->l+1)*qpow(itl->v,LL(ex),LL(mod))) %mod;
return res;
}
int n,m;
LL seed,vmax;
LL rd(){
LL ret=seed;
seed=(seed*7+13)%MOD7;
return ret;
}
LL a[MAXN];
int main(){
cin>>n>>m>>seed>>vmax;
for(int i=1;i<=n;i++){
a[i]=(rd()%vmax)+1;
s.insert(node(i,i,a[i]));
}
s.insert(node(n+1,n+1,0));
int lines=0;
for(int i=1;i<=m;i++){
//-----------------------------
int op=int(rd()%4)+1;
int l=int(rd()%n)+1;
int r=int(rd()%n)+1;
if(l>r)swap(l,r);
int x,y;
if(op==3)x=int(rd()%(r-l+1))+1;
else x=int(rd()%vmax)+1;
if(op==4)y=int(rd()%vmax)+1;
//------------------------------以上为题目要求生成数据
if(op==1)add(l,r,LL(x));
else if(op==2)assign_val(l,r,LL(x));
else if(op==3)cout<<ranks(l,r,x)<<endl;
else cout<<sum(l,r,x,y)<<endl;
}
return 0;
}
---->例题2(给定每次操作)传送门
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
#define IT set::iterator
struct node{
int l,r;
mutable LL v;
node(int L,int R=-1,LL V=0):l(L),r(R),v(V){}
bool operator<(const node &o)const{
return l<o.l;
}
};
LL qpow(LL a,LL b,LL mod){//快速幂
LL ans=1;
LL x=a%mod;
while(b){
if(b&1)ans=ans*x%mod;
x=x*x%mod;
b>>=1;
}
return ans;
}
set<node>s;
IT split(int pos){
IT it=s.lower_bound(node(pos));
if(it!=s.end()&&it->l==pos)return it;
--it;
int L=it->l,R=it->r;
LL V=it->v;
s.erase(it);
s.insert(node(L,pos-1,V));
return s.insert(node(pos,R,V)).first;
}
void add(int l,int r,LL val){//给l到r所有数加上val
IT itr=split(r+1),itl=split(l);
for(;itl!=itr;++itl)
itl->v=(itl->v+val)%10007;
}
void muti(int l,int r,LL val){//给l到r所有数乘上val
IT itr=split(r+1),itl=split(l);
for(;itl!=itr;++itl)
itl->v=(itl->v*val)%10007;
}
void assign_val(int l,int r,LL val){//把l到r所有数改为val
IT itr=split(r+1),itl=split(l);
s.erase(itl,itr);
s.insert(node(l,r,val));
}
LL sum(int l,int r,int ex){//询问l到r每个数字的x次方和
IT itr=split(r+1),itl=split(l);
LL res=0;
for(;itl!=itr;++itl)
res=(res+(long long)(itl->r - itl->l+1)*qpow(itl->v,(long long)ex,10007))%10007;
return res;
}
int n,m;
int main(){
while(cin>>n>>m,n!=0||m!=0){
s.clear();
s.insert(node(1,n,0));
s.insert(node(n+1,n+1,0));
int opt,x,y;
long long z;
for(int i=1;i<=m;i++){
scanf("%d%d%d%lld",&opt,&x,&y,&z);
if(opt==1)add(x,y,z);else
if(opt==2)muti(x,y,z);else
if(opt==3)assign_val(x,y,z);else
printf("%lld\n",sum(x,y,z));
}
}
return 0;
}
加减乘除、取余、乘方、快速幂、cin,cout、比较大小、int转化
class BigNum{
private:
#define MAXN 9999
#define MAXSIZE 1500
#define DLEN 4
int a[MAXSIZE]; //可以控制大数的位数
int len; //大数长度
public:
BigNum(){len=1;memset(a,0,sizeof(a));}//构造函数
BigNum(const int); //将一个int类型的变量转化为大数
BigNum(const char*); //将一个字符串类型的变量转化为大数
BigNum(const BigNum &); //拷贝构造函数
BigNum &operator=(const BigNum &); //重载赋值运算符,大数之间进行赋值运算
friend istream& operator>>(istream&, BigNum&); //重载输入运算符
friend ostream& operator<<(ostream&, BigNum&); //重载输出运算符
BigNum operator+(const BigNum &) const; //重载加法运算符,两个大数之间的相加运算
BigNum operator-(const BigNum &) const; //重载减法运算符,两个大数之间的相减运算
BigNum operator*(const BigNum &) const; //重载乘法运算符,两个大数之间的相乘运算
BigNum operator/(const int &) const; //重载除法运算符,大数对一个整数进行相除运算
BigNum operator^(const int &) const; //大数的n次方运算
int operator%(const int &) const; //大数对一个int类型的变量进行取模运算
bool operator>(const BigNum &T)const; //大数和另一个大数的大小比较
bool operator>(const int &t)const; //大数和一个int类型的变量的大小比较
void print(); //输出大数
};
BigNum BigNum_qpow(BigNum x,BigNum e);//大数快速幂
BigNum::BigNum(const int b){//将一个int类型的变量转化为大数
int c,d=b;
len=0;
memset(a,0,sizeof(a));
while(d>MAXN){
c=d-(d/(MAXN+1))*(MAXN+1);
d=d/(MAXN+1);
a[len++]=c;
}
a[len++]=d;
}
BigNum::BigNum(const char*s){//将一个字符串类型的变量转化为大数
int t,k,index,l,i;
memset(a,0,sizeof(a));
l=strlen(s);
len=l/DLEN;
if(l%DLEN)len++;
index=0;
for(i=l-1;i>=0;i-=DLEN){
t=0;
k=i-DLEN+1;
if(k<0)k=0;
for(int j=k;j<=i;j++)t=t*10+s[j]-'0';
a[index++]=t;
}
}
BigNum::BigNum(const BigNum &T):len(T.len){ //拷贝构造函数
int i;
memset(a,0,sizeof(a));
for(i=0;i<len;i++)a[i]=T.a[i];
}
BigNum & BigNum::operator=(const BigNum &n){//重载赋值运算符,大数之间进行赋值运算
int i;
len=n.len;
memset(a,0,sizeof(a));
for(i=0;i<len;i++)a[i]=n.a[i];
return *this;
}
istream& operator>>(istream &in,BigNum &b){//重载输入运算符
char ch[MAXSIZE*4];
int i=-1;
in>>ch;
int l=strlen(ch);
int count=0,sum=0;
for(i=l-1;i>=0;){
sum=0;
int t=1;
for(int j=0;j<4&&i>=0;j++,i--,t*=10){
sum+=(ch[i]-'0')*t;
}
b.a[count]=sum;
count++;
}
b.len=count++;
return in;
}
ostream& operator<<(ostream &out,BigNum &b){//重载输出运算符
int i;
cout<<b.a[b.len-1];
for(i=b.len-2;i>=0;i--){
cout.width(DLEN);
cout.fill('0');
cout<<b.a[i];
}
return out;
}
BigNum BigNum::operator+(const BigNum &T)const{//两个大数之间的相加运算
BigNum t(*this);
int i,big; //位数
big=T.len>len?T.len:len;
for(i=0;i<big;i++){
t.a[i]+=T.a[i];
if(t.a[i]>MAXN){
t.a[i+1]++;
t.a[i]-=MAXN+1;
}
}
if(t.a[big]!=0)t.len=big+1;
else t.len=big;
return t;
}
BigNum BigNum::operator-(const BigNum &T)const{//两个大数之间的相减运算
int i,j,big;
bool flag;
BigNum t1,t2;
if(*this>T){
t1=*this;
t2=T;
flag=0;
}else{
t1=T;
t2=*this;
flag=1;
}
big=t1.len;
for(i=0;i<big;i++){
if(t1.a[i]<t2.a[i]){
j=i+1;
while(t1.a[j]==0)j++;
t1.a[j--]--;
while(j > i)t1.a[j--]+=MAXN;
t1.a[i]+=MAXN+1-t2.a[i];
}
else t1.a[i]-=t2.a[i];
}
t1.len=big;
while(t1.a[len-1]==0&&t1.len>1){
t1.len--;
big--;
}
if(flag)t1.a[big-1]=0-t1.a[big-1];
return t1;
}
BigNum BigNum::operator*(const BigNum &T)const{//两个大数之间的相乘运算
BigNum ret;
int i,j,up;
int temp,temp1;
for(i=0;i<len;i++){
up=0;
for(j=0;j<T.len;j++){
temp=a[i]*T.a[j]+ret.a[i + j]+up;
if(temp>MAXN){
temp1=temp-temp/(MAXN+1)*(MAXN + 1);
up=temp/(MAXN+1);
ret.a[i+j]=temp1;
}else{
up=0;
ret.a[i+j]=temp;
}
}
if(up!=0)ret.a[i+j]=up;
}
ret.len=i+j;
while(ret.a[ret.len-1]==0&&ret.len>1)ret.len--;
return ret;
}
BigNum BigNum::operator/(const int &b)const{//大数对一个整数进行相除运算
BigNum ret;
int i,down=0;
for(i=len-1;i>=0;i--){
ret.a[i]=(a[i]+down*(MAXN+1))/b;
down=a[i]+down*(MAXN+1)-ret.a[i]*b;
}
ret.len=len;
while(ret.a[ret.len-1]==0&&ret.len>1)ret.len--;
return ret;
}
int BigNum::operator %(const int &b)const{//大数对一个int类型的变量进行取模运算
int i,d=0;
for (i=len-1;i>=0;i--){
d=((d*(MAXN+1))%b+a[i])%b;
}
return d;
}
BigNum BigNum::operator^(const int &n)const{//大数的n次方运算
BigNum t,ret(1);
int i;
if(n<0)exit(-1);
if(n==0)return 1;
if(n==1)return *this;
int m=n;
while(m>1){
t=*this;
for(i=1;i<<1<=m;i<<=1){
t=t*t;
}
m-=i;
ret=ret*t;
if(m==1)ret=ret*(*this);
}
return ret;
}
BigNum BigNum_qpow(BigNum x,BigNum e){//大数快速幂
BigNum re(1);
while(e>0){
if(e%2)re=re*x;
x=x*x;
e=e/2;
}
return re;
}
bool BigNum::operator>(const BigNum &T)const{//大数和另一个大数的大小比较
int ln;
if(len>T.len)return true;
else if(len==T.len){
ln=len-1;
while(a[ln]==T.a[ln]&&ln>=0)ln--;
if(ln>=0&&a[ln]>T.a[ln])return true;
else return false;
}
else return false;
}
bool BigNum::operator>(const int &t)const{//大数和一个int类型的变量的大小比较
BigNum b(t);
return *this>b;
}
void BigNum::print(){//输出大数
int i;
cout<<a[len-1];
for(i=len-2;i>=0;i--){
cout.width(DLEN);
cout.fill('0');
cout<<a[i];
}
cout<<endl;
}
const double eps=1e-8;
int eps_cmp(double x){return (x>eps)-(x<-eps);} //误差范围内相等返回0
struct point{
double x,y;
point(){}
point(double _x,double _y){x=_x;y=_y;}
point operator -(const point &b)const{
return point(x-b.x,y-b.y);
}
bool operator ==(const point &b)const{
return eps_cmp(x-b.x)==0&&eps_cmp(y-b.y)==0;
}
bool operator <(const point &b)const{
return x<b.x||x==b.x&&y<b.y;
}
double operator *(const point &b)const{//叉积
return x*b.y-b.x*y;
}
double mod(){return sqrt(x*x+y*y);}
}
C++11中,容器内元素可以用
for(auto &i:a)遍历 //加&是引用(可以修改值),不加只能访问,不能修改
注意,低于c++11的版本需要在编译选项里加上 -std=c++11这句话
分配大小
vector<int>a(n);
二维vector分配大小
vector<vector<int> >d(n,vector<int>(m));
详解链接
(map是用R-B tree写的,存储按key排序,操作时间复杂度大都是logn)
map的键和值是唯一的,而如果一个键需要对应多个值,就只能用multimap
1.定义
map<type1,type2>mp; //type1是key type2是value
2.map容器内元素的访问
①通过下标访问
注意:map的键是唯一的
mp['c']=20;
②通过迭代器访问
定义方式与其他STL容器迭代器相同:
map<type1,type2>::iterator it=mp.find(...);
it->fitst对应key,it->second对应value
3.map常用函数
①插入insert
// 第一种 用insert函數插入pair(已出现的不能覆盖)
mapStudent.insert(pair<int, string>(000, "student_zero"));
// 第二种 用insert函数插入value_type数据(已出现的不能覆盖)
mapStudent.insert(map<int, string>::value_type(001, "student_one"));
// 第三种 用"array"方式插入(可覆盖已出现的)
mapStudent[123] = "student_first";
mapStudent[456] = "student_second";
②查找
// find 返回迭代器指向当前查找元素的位置否则返回map::end()位置
map<type1,type2>::iterator iter = mapStudent.find("123");
if(iter != mapStudent.end())
cout<<"Find, the value is"<<iter->second<<endl;
else
cout<<"Do not Find"<<endl;
④删除
//迭代器刪除
iter = mapStudent.find("123");
mapStudent.erase(iter);
//用关键字刪除
int n = mapStudent.erase("123"); //如果刪除了會返回1,否則返回0
//用迭代器范围刪除 : 把整个map清空
mapStudent.erase(mapStudent.begin(), mapStudent.end());
//等同于mapStudent.clear()
⑤大小
int nSize = mapStudent.size();
4.所有函数
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数
1、set中的元素都是排好序的
2、set集合中没有重复的元素
3、set中数元素的值不能直接被改变
迭代器 set<int>iterator:: it=
insert() 插入
lower_bound() 返回值>=给定元素的第一个位置
upper_bound() 返回值>给定元素的第一个位置
begin() 返回set容器第一个元素的迭代器
end() 返回一个指向当前set末尾元素的下一位置的迭代器.
clear() 删除set容器中的所有的元素
empty() 判断set容器是否为空
size() 返回当前set容器中的元素个数