BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)

BZOJ
洛谷

一直觉得自己非常zz呢。现在看来是真的=-=


注意题意描述有点问题,可以看BZOJ/洛谷讨论。
每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R]\)
每个物品都是在一个时间点发生的(并不是区间,我竟然一直没想通= =)。那么就可以按时间线段树分治了。
把每个询问按时间区间放到线段树对应节点上。那么在每个节点处,把时间点在该区间内的物品,按编号从小到大插入到可持久化\(Trie\)里,就可以解决这个节点上的询问了。
排序可以在最开始将物品按编号排序,分治时直接根据时间点划分到左右两个子区间继续处理。


//39092kb   3156ms
#include 
#include 
#include 
#include 
#include 
#define gc() getchar()
#define BIT 16
#define MAXIN 500000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e5+5;

int root[N],Ans[N];
char IN[MAXIN],*SS=IN,*TT=IN;
struct OPT
{
    int t,id,v;
    bool operator <(const OPT &x)const
    {
        return id>i&1, son[x][c^1]=son[y][c^1], x=son[x][c]=++tot, y=son[y][c], sz[x]=sz[y]+1;
    }
    int Query(int x,int y,int v)//y-x
    {
        int res=0;
        for(int i=BIT,c; ~i; --i)
        {
            c=(v>>i&1)^1;
            if(sz[son[y][c]]-sz[son[x][c]]>0) res|=1< vec[S];
    #undef S
    void Modify(int l,int r,int rt,int L,int R,int v)
    {
        if(L<=l && r<=R) {vec[rt].push_back(v); return;}
        int m=l+r>>1;
        if(L<=m) Modify(lson,L,R,v);
        if(m>1]<=x) ans=mid,l=mid+1;
            else r=mid-1;
        return ans;
    }
    void Solve(int L,int R,const std::vector &v)
    {
        Trie.tot=0; int t=0;
        for(int i=L; i<=R; ++i) A[++t]=opt[i].id, Trie.Insert(root[t],root[t-1],opt[i].v);
        for(int i=0,lim=v.size(),id; iR) return;
        if(vec[rt].size()) Solve(L,R,vec[rt]);
        if(l==r) return;
        int m=l+r>>1,t1=0,t2=0;
        for(int i=L; i<=R; ++i) opt[i].t<=m?(tmp1[t1++]=opt[i],0):(tmp2[t2++]=opt[i],0);
        for(int i=0,p=L; i

你可能感兴趣的:(BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie))