题解 P3168 【[CQOI2015]任务查询系统】
主席树题,做差分统计,在差分树上操作,一边操作一边“滚动”。仅当i时刻的所有操作结束,将i作为i+1的原版。
统计答案时在线段树上二分就可以。注意一点,可能存在相同的优先级,比如说优先级可以使 2 3 3 4 6,这样查K = 2的时候答案不是值域线段树上2和3的位置的SUM,而是2的SUM加上剩余排名个数个3,详见代码。
离散化,数据太大了,我用的是sort+unique+map,清一色的STL,map有点慢,注意一下,能少用就少用,一开始就因为map所以TLE好久……
至于空间范围,告诉你们,很大,原题应该是512MB,不知道这里是多少,起码8*10^6没有问题,不要开到4*10^6以下,那样就RE了。
好了,各种问题都说了,不要问我怎么知道的,看看提交记录。
下面是代码。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
#define MAXT 8000000
#define MAXN 100000
#define ll long long
#define lc(x) t[x].lc
#define rc(x) t[x].rc
#define mx(x) t[x].mx
#define sum(x) t[x].sum
#define mid ((lef+rig)>>1)
#define sgn(x) (x > 0 ? 1 : -1)
struct Node
{
ll mx,sum;
int lc,rc;
Node(){}
Node(ll a, ll b)
{
mx = a, sum = b;
return;
}
};
ll dat[MAXN*4+5], tot, Pre = 1, n, k, op, tm, s, e, p;
Node t[MAXT+5];
map<ll,ll> h;
struct Segment_Tree
{
int root;
inline Node Merge(Node a, Node b)
{
a.mx += b.mx, a.sum += b.sum;
return a;
}
inline void Push(int p)
{
mx(p) = mx(lc(p)) + mx(rc(p)), sum(p) = sum(lc(p)) + sum(rc(p));
return;
}
inline void Init(int x = -1)
{
root = tot++;
if(x+1)
t[root] = t[x];
return;
}
Node Query(int p, int lef, int rig, int L, int R)
{
if(!p || lef > rig)
return Node(0ll,0ll);
if(L == lef && R == rig)
return t[p];
if(R <= mid)
return Query(lc(p),lef,mid,L,R);
if(L > mid)
return Query(rc(p),mid+1,rig,L,R);
return Merge(Query(lc(p),lef,mid,L,mid) , Query(rc(p),mid+1,rig,mid+1,R));
}
void Edit(int p, int lef, int rig, int x, int tag)
{
if(lef == rig)
{
mx(p) += tag, sum(p) += tag*dat[lef];
return;
}
int temp = tot++;
if(x <= mid)
t[temp] = t[lc(p)], lc(p) = temp, Edit(lc(p),lef,mid,x,tag);
else
t[temp] = t[rc(p)], rc(p) = temp, Edit(rc(p),mid+1,rig,x,tag);
Push(p);
return;
}
};
Segment_Tree T[MAXN+5];
struct Task
{
ll pos,val;
}X[MAXN*2+5];
inline bool operator < (Task a, Task b)
{
return a.pos < b.pos;
}
inline ll Search(ll ti, ll rank)
{
ll lef = 1, rig = k;
for(Node midd; lef < rig; )
{
midd = T[ti].Query(T[ti].root,1,k,1,mid);
if(midd.mx >= rank)
rig = mid;
else
lef = mid+1;
}
Node res = T[ti].Query(T[ti].root,1,k,1,lef-1);
Node poi = T[ti].Query(T[ti].root,1,k,lef,lef);
Pre = res.sum;
if(rank <= res.mx+poi.mx)
Pre += dat[lef]*(rank-res.mx);
return Pre;
}
inline ll read()
{
ll ans=0;
char last=' ',ch=getchar();
while(ch<'0' || ch>'9') last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans;
return ans;
}
void out(ll x)
{
if(x<0)putchar('-'),x=-x;
if(x<10)
putchar(x+'0');
else{
out(x/10);
putchar(x%10+'0');
}
return;
}
int main()
{
n = read(), tm = read();
for(register int i = op = k = 1; i <= n; i++)
s = read(), e = read(), p = read(), dat[k++] = p,
X[op].pos = s, X[op++].val = p, X[op].pos = e+1, X[op++].val = -p;
sort(X+1,X+op), op--, sort(dat+1,dat+k), k = unique(dat+1,dat+k)-dat-1;
for(register int i = 1; i <= k; i++)
h[dat[i]] = i;
T[0].Init();
for(register int i = 1, j = 1; i <= tm; i++)
{
T[i].Init(T[i-1].root);
for(; X[j].pos == i; j++)
T[i].Edit(T[i].root,1,k,h[abs(X[j].val)],sgn(X[j].val));
}
for(ll x, a, b, c; tm--; out(Search(x,1+(a*Pre+b)%c)),putchar('\n'))
x = read(), a = read(), b = read(), c = read();
return 0;
}
看到有些代码,没用主席树,直接奇迹般暴力O(nm)水过了。敲了3个小时的我表示无语。