poj-3667–hotel
整体来说思路不难想,就是细节比较多,处理复杂,容易出错
题意:给出长为n的空间大小,支持两种操作
1.给定长度len,尽可能填补靠左边的空间,并输出填补的起始位置
2.给定起始位置pos,以及长度len,将以pos为起始长度为len的空间清空
思路:
变量记录:
维护三颗线段树,seg_left[root]表示结点root对应的区间[l,r]上,从左端点l起始的空闲空间长度,seg_right[root]表示结点root对应的区间[l,r]上,从右端点r起始的空闲空间长度,seg_tree[root]表示结点root对应的区间[l,r]上,对应的最大的连续空闲长度。
lazy[root]表示结点root对应的区间[l,r]上,对应的懒标记,这里需要注意的点是,有三种状态,值为2时表示root结点下的子树都为被占状态,值为1时表示root结点下的子树都为空闲状态,两种后来的可以覆盖前面的,值为0表示没有进行标记。
细节处理方面比较多:
1.push_up向上回溯的处理
2.query查询时的处理,先查左子树,再查左子树加上右子树,最后查右子树
3.lazy tag的部分,push_down向下push比较简单,就是将三颗树的值都置为lazy的值就可以。
//#include <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N = 2e5+10;
int n;
int arr[N],seg_tree[N<<2],lazy[N<<2],seg_left[N<<2],seg_right[N<<2];
void push_up(int root,int L,int R)
{
seg_tree[root]=seg_right[root<<1]+seg_left[root<<1|1];
seg_tree[root]=max(seg_tree[root],max(seg_tree[root<<1],seg_tree[root<<1|1]));
int mid=L+R>>1;
if(seg_left[root<<1]==mid-L+1)
seg_left[root]=seg_left[root<<1]+seg_left[root<<1|1];
else seg_left[root]=seg_left[root<<1];
if(seg_right[root<<1|1]==R-mid)
seg_right[root]=seg_right[root<<1]+seg_right[root<<1|1];
else seg_right[root]=seg_right[root<<1|1];
}
void build(int root,int L,int R)
{
if(L==R)
{
seg_tree[root]=1;
seg_left[root]=1;
seg_right[root]=1;
return ;
}
int mid=(L+R)>>1;
build(root<<1,L,mid);
build(root<<1|1,mid+1,R);
push_up(root,L,R);
}
void add(int root,int L,int R,int val)
{
seg_tree[root]=(val-1)*(R-L+1);
seg_left[root]=(val-1)*(R-L+1);
seg_right[root]=(val-1)*(R-L+1);
}
void push_down(int root,int L,int R)
{
if(lazy[root])
{
int mid=L+R>>1;
lazy[root<<1]=lazy[root];
lazy[root<<1|1]=lazy[root];
add(root<<1,L,mid,lazy[root]);
add(root<<1|1,mid+1,R,lazy[root]);
lazy[root]=0;
}
}
void update_Interval(int root,int L,int R,int LL,int RR,int val)
{
if(LL>R||RR<L)return ;
int mid=L+R>>1;
if(LL<=L&&RR>=R)
{
//if(L==R&&L==6)cout<<"fuck"<<endl;
lazy[root]=val;
seg_tree[root]=(R-L+1)*(val-1);
seg_left[root]=(R-L+1)*(val-1);
seg_right[root]=(R-L+1)*(val-1);
//lazy标记只是标记当前已加了值,但是还没下传的,所以这里不是*lazy[root]
//lazy[root]表示的是儿子节点需要加的值
return ;
}
//up和down需要对应,因为up是通过儿子结点对当前节点进行更新
//所以,pushdown要保证儿子的值已经更新了。
push_down(root,L,R);
update_Interval(root<<1,L,mid,LL,RR,val);
update_Interval(root<<1|1,mid+1,R,LL,RR,val);
push_up(root,L,R);
}
int ans;
void query(int root,int L,int R,int LL,int RR,int x)
{
if(LL>R||RR<L)return ;
/*if(x==4)
cout<<L<<" "<<R<<" "<<seg_tree[root]<<endl;*/
int mid=L+R>>1;
push_down(root,L,R);
if(LL<=L&&RR>=R)
{
if(L==R)
{
ans=L;
update_Interval(1,1,n,L,L,1);
return ;
}
if(seg_tree[root<<1]>=x)
{
query(root<<1,L,mid,LL,RR,x);
}
else if(seg_right[root<<1]+seg_left[root<<1|1]>=x)
{
int pos;
pos=mid-seg_right[root<<1]+1;
//cout<<"update"<<pos<<pos+x-1<<endl;
update_Interval(1,1,n,pos,pos+x-1,1);
ans=pos;
return ;
}
else
{
query(root<<1|1,mid+1,R,LL,RR,x);
}
}
//push_down(root,L,R);
push_up(root,L,R);
//return min(query(root<<1,L,mid,LL,RR,x),query(root<<1|1,mid+1,R,LL,RR,x));
}
void update(int root,int L,int R,int pos,int val)
{
if(pos<L||pos>R)return ;
if(L==R&&L==pos)
{
seg_tree[root]=val;
return ;
}
int mid=L+R>>1;
update(root<<1,L,mid,pos,val);
update(root<<1|1,mid+1,R,pos,val);
push_up(root,L,R);
}
void func()
{
cout<<"-------start--------------"<<endl;
cout<<seg_tree[1]<<endl;
cout<<seg_tree[2]<<" "<<seg_tree[3]<<endl;
cout<<seg_tree[4]<<" "<<seg_tree[5]<<" "<<seg_tree[6]<<" "<<seg_tree[7]<<endl;
/*cout<<seg_tree[3]<<endl;
cout<<seg_tree[6]<<" "<<seg_tree[7]<<endl;
cout<<seg_tree[12]<<" "<<seg_tree[13]<<" "<<seg_tree[14]<<" "<<seg_tree[15]<<endl;
cout<<"--------end---------------"<<endl;*/
}
signed main()
{
ios
int m;
cin>>n>>m;
build(1,1,n);
while(m--)
{
int flag,x,y;
cin>>flag;
if(flag==1)
{
cin>>x;
if(seg_tree[1]<x)
{
cout<<0<<endl;
}
else
{
query(1,1,n,1,n,x);
cout<<ans<<endl;
}
//cout<<seg_tree[1]<<endl;
}
else
{
cin>>x>>y;
update_Interval(1,1,n,x,x+y-1,2);
}
/*cout<<"总共 "<<seg_tree[1]<<endl;
func();*/
}
return 0;
}
/*
9 100
1 3
1 3
1 3
2 1 9
1 3
*/
icpc网络预选赛②L Euler Function
思路:
由将要乘的数分解质因数,一个一个乘,对于因子已经包含x的区间,直接裸区间乘,不包含的区间,可以再次深入找,直到单点修改(为什么这样不超时,因为100以内只有25个质数,区间范围为1e5,也就是说最多单点修改251e5log1e5次,是可以的)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N = 1e5+10;
int arr[N],lazy[N<<2],seg_tree[N<<2];
int n,m,p=998244353;
int seg_vis[N][30];
int fi[101];
int prime[30];
int inde;
int prime_index[105];//素数的位置,例如prime_index[2]=0
struct node
{
int zhi[30];
int len;
}fenjie[105];
void fenjiezhi()
{
for(int i=2;i<=100;i++)
{
int j=0;
int x=i;
while(j<inde&&x!=1)
{
if(x%prime[j]==0)
{
fenjie[i].zhi[fenjie[i].len++]=prime[j];
while(x%prime[j]==0)
{
x/=prime[j];
}
}
j++;
}
}
}
void push_up(int root,int L,int R)
{
seg_tree[root]=(seg_tree[root<<1]+seg_tree[root<<1|1])%p;
for(int i=0;i<25;i++)
{
seg_vis[root][i]=min(seg_vis[root<<1][i],seg_vis[root<<1|1][i]);
}
}
void build(int root,int L,int R)
{
lazy[root]=1;
if(L==R)
{
int x=arr[L];
seg_tree[root]=x;
for(int i=0;i<fenjie[x].len;i++)
{
int tmp_prime=fenjie[x].zhi[i];
seg_vis[root][prime_index[tmp_prime]]=1;
seg_tree[root]=seg_tree[root]*(tmp_prime-1)/tmp_prime;
}
return ;
}
int mid=(L+R)>>1;
build(root<<1,L,mid);
build(root<<1|1,mid+1,R);
push_up(root,L,R);
}
void add(int root,int L,int R,int val)
{
lazy[root]=lazy[root]*val%p;
seg_tree[root]=seg_tree[root]*val%p;
}
void push_down(int root,int L,int R)
{
//if(lazy[root]!=0)
//if(root==2)cout<<"fuck"<<lazy[root][0]<<endl;
if(lazy[root]!=1)
{
int mid=L+R>>1;
add(root<<1,L,mid,lazy[root]);
add(root<<1|1,mid+1,R,lazy[root]);
}
lazy[root]=1;
//if(root==2)cout<<"fuck"<<lazy[root][0]<<endl;
}
void update_Interval(int root,int L,int R,int LL,int RR,int val)
{
if(LL>R||RR<L)return ;
//cout<<L<<" "<<R<<endl;
int mid=L+R>>1;
if(LL<=L&&RR>=R)
{
int index=prime_index[val];//得到质数的下标
if(L==R)
{
if(seg_vis[root][index]==1)seg_tree[root]=seg_tree[root]*(val)%p;
else seg_tree[root]=seg_tree[root]*(val-1)%p;
seg_vis[root][index]=1;
return ;
}
if(seg_vis[root][index])
{
seg_tree[root]=seg_tree[root]*val%p;
lazy[root]=lazy[root]*val%p;
return ;
}
//lazy标记只是标记当前已加了值,但是还没下传的,所以这里不是*lazy[root]
//lazy[root]表示的是儿子节点需要加的值
}
//up和down需要对应,因为up是通过儿子结点对当前节点进行更新
//所以,pushdown要保证儿子的值已经更新了。
push_down(root,L,R);
update_Interval(root<<1,L,mid,LL,RR,val);
update_Interval(root<<1|1,mid+1,R,LL,RR,val);
push_up(root,L,R);
}
int query(int root,int L,int R,int LL,int RR)
{
if(LL>R||RR<L)return 0;
int mid=L+R>>1;
if(LL<=L&&RR>=R)
{
return seg_tree[root]%p;
}
push_down(root,L,R);
return (query(root<<1,L,mid,LL,RR)+query(root<<1|1,mid+1,R,LL,RR))%p;
}
/*
void update(int root,int L,int R,int pos,int val)
{
if(pos<L||pos>R)return ;
if(L==R&&L==pos)
{
seg_tree[root]=val;
arr[L]=val;
return ;
}
int mid=L+R>>1;
update(root<<1,L,mid,pos,val);
update(root<<1|1,mid+1,R,pos,val);
push_up(root,L,R);
}
void func()
{
cout<<"-------start--------------"<<endl;
cout<<seg_tree[1]<<endl;
cout<<seg_tree[2]<<" "<<seg_tree[3]<<endl;
cout<<seg_tree[4]<<" "<<seg_tree[5]<<" "<<seg_tree[6]<<" "<<seg_tree[7]<<endl;
cout<<seg_tree[8]<<" "<<seg_tree[9]<<endl;
cout<<"--------end---------------"<<endl;
cout<<seg_tree[3]<<endl;
cout<<seg_tree[6]<<" "<<seg_tree[7]<<endl;
cout<<seg_tree[12]<<" "<<seg_tree[13]<<" "<<seg_tree[14]<<" "<<seg_tree[15]<<endl;
}*/
signed main()
{
ios
for(int i=1;i<=100;i++)
{
int sum=1;
//int flag=1;
for(int j=2;j<i;j++)
{
if(__gcd(i,j)==1)sum++;
}
fi[i]=sum;
if(fi[i]==i-1)
{
prime[inde]=i;
prime_index[i]=inde++;
}
//cout<<i<<" "<<sum<<endl;
}
//cout<<inde<<endl;
fenjiezhi();
//for(int i=0;i<=100;i++)
//cout<<"i="<<i<<" "<<prime_index[i]<<endl;
//cout<<fenjie[8].len;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>arr[i];
build(1,1,n);
//func();
while(m--)
{
int flag,x,y,k;
cin>>flag;
if(flag==0)
{
cin>>x>>y>>k;
int zhi=k;
for(int i=0;i<fenjie[k].len;i++)
{
int tmp_prime=fenjie[k].zhi[i];//分解的每一个质数
//lazy[root][index]++;//对应的懒标记++记录
while(zhi%tmp_prime==0)
{
update_Interval(1,1,n,x,y,tmp_prime);
zhi/=tmp_prime;
}
}
}
else
{
cin>>x>>y;
cout<<query(1,1,n,x,y)<<endl;
}
//func();
}
return 0;
}
/*
*/