uoj#218. 【UNR #1】火车管理
题目描述
n,m<=5e5,x<=1e3
题解
想了一下就想出了log^2的,之后刚了一个下午尝试去掉一个log结果发现把set改成优先队列就过了
log^2的自然做法:
在线段树上set里挂加进去的数,如果下传的话时间会假,因此不下传标记
弹栈就单点查询,把经过的所有区间内时间最大的弹掉,第二大的就是新的值
弹掉之后下传,注意只需要下传一个标记,往下一共有log个区间
时间是log^2的,用优先队列即可通过并且不是最慢
题解一个log的自然做法:
主席树直接维护每个时刻的栈顶(时间/值),弹栈等于把某个位置修改为某个时间该位置的值,直接查询即可
简单自然
code
log^2
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
//#define file
using namespace std;
int n,m,tp,Tp,i,j,k,l,x,y,z,ans,T,Find;
char st[21],ch;
struct type{int x,t;} Find2;
bool operator < (type a,type b) {return a.t<b.t;}
struct tree1{
int tr[2000001],Tr[2000001];
void down(int t,int len)
{
if (Tr[t]>-1)
{
if (len>1) Tr[t*2]=Tr[t*2+1]=Tr[t];
tr[t]=Tr[t]*len;Tr[t]=-1;
}
}
void change(int t,int l,int r,int x,int y,int s)
{
int mid=(l+r)/2;
down(t,r-l+1);
if (x<=l && r<=y)
{
Tr[t]=s,down(t,r-l+1);
return;
}
down(t*2,mid-l+1),down(t*2+1,r-mid);
if (x<=mid) change(t*2,l,mid,x,y,s);
if (mid<y) change(t*2+1,mid+1,r,x,y,s);
tr[t]=tr[t*2]+tr[t*2+1];
}
int find(int t,int l,int r,int x,int y)
{
int mid=(l+r)/2,ans=0;
down(t,r-l+1);
if (x<=l && r<=y) return tr[t];
if (x<=mid) ans+=find(t*2,l,mid,x,y);
if (mid<y) ans+=find(t*2+1,mid+1,r,x,y);
return ans;
}
} t1;
struct tree2{
priority_queue<type> tr[2000001];
void change(int t,int l,int r,int x,int y,type s)
{
int mid=(l+r)/2;
if (x<=l && r<=y) {tr[t].push(s);return;}
if (x<=mid) change(t*2,l,mid,x,y,s);
if (mid<y) change(t*2+1,mid+1,r,x,y,s);
}
void find(int t,int l,int r,int x)
{
int mid=(l+r)/2;
type s;
if (!tr[t].empty())
{
s=tr[t].top();
if (s.t>Find2.t) Find=t,Find2=s;
}
if (l==r) return;
if (x<=mid) find(t*2,l,mid,x);
else find(t*2+1,mid+1,r,x);
}
void Change(int t,int l,int r,int x,type s)
{
int mid=(l+r)/2;
if (l==r) return;
if (x<=mid)
{
if (t>=Find) tr[t*2+1].push(s);
Change(t*2,l,mid,x,s);
}
else
{
if (t>=Find) tr[t*2].push(s);
Change(t*2+1,mid+1,r,x,s);
}
}
} t2;
void Read(int &x) {x=0; ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();}
void Write(int x) {int i=0; if (!x) {putchar('0');putchar('\n');return;} while (x) st[++i]=x%10+'0',x/=10; while (i) putchar(st[i--]);putchar('\n');}
int main()
{
#ifdef file
freopen("uoj218.in","r",stdin);
freopen("uoj218.out","w",stdout);
#endif
memset(t1.Tr,255,sizeof(t1.Tr));
Read(n),Read(m),Read(tp);
fo(T,1,m)
{
Read(Tp);
switch (Tp)
{
case 1:{
Read(j);Read(k);j=(j+ans*tp)%n+1;k=(k+ans*tp)%n+1;
x=min(j,k),y=max(j,k);
ans=t1.find(1,1,n,x,y);
Write(ans);
break;
}
case 2:{
Read(x);x=(x+ans*tp)%n+1;Find=0;Find2.t=-1;
t2.find(1,1,n,x);
if (Find)
{
t2.tr[Find].pop();
t2.Change(1,1,n,x,Find2);
Find=0;Find2={0,-1};
t2.find(1,1,n,x);
t1.change(1,1,n,x,x,Find2.x);
}
break;
}
case 3:{
Read(j),Read(k),Read(z);j=(j+ans*tp)%n+1;k=(k+ans*tp)%n+1;
x=min(j,k),y=max(j,k);
t1.change(1,1,n,x,y,z);
t2.change(1,1,n,x,y,{z,T});
break;
}
}
}
fclose(stdin);
fclose(stdout);
return 0;
}