区间查询[2009国家集训队]小Z的袜子(hose)

PS:今天上午,非常郁闷,有很多简单基础的问题搞得我有些迷茫,哎,代码几天不写就忘。目前又不当COO,还是得用心记代码哦!

    转载请注明出处,感谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

    

恐怖的莫队法算。。。觉感有了这个,是不是可以决解全部的区间查询但是无修改的目题

    

许也不是最优的,但是O(n*sqrt(n))全完也是可以实验的。

    


    

莫队法算:对于两个区间的查询[l1,r1] ,[l2,r2]如果每加增一个区间元素或者删除,都能做到O(1)的话

    

那么从[l1,r1]转移到[l2,r2],暴力可以做到|l1-l2|+|r1-r2|,就是manhattan距离

    

莫队的论文始终没有找到,所以只是大致的了解下,应该是证明出结构出哈密尔顿路径是最优的。

    

但是可以用manhattan mst来结构,大约会是两倍,然后莫队证明出这样转移的限上是O(n*sqrt(n))。

    

所以对于这类无修改的区间查询说来

    

可以先将全部的区间,当作维二平面上的点,求一次manhattan mst,然后根据mst来行进转移

    

相邻的两个区间的查询转移,暴力决解。

    

Manhattan MST 这里有
    每日一道理
时间好比一条小溪,它能招引我们奔向生活的海洋;时间如同一叶扁舟,它将帮助我们驶向理想的彼岸;时间犹如一支画笔,它会指点我们描绘人生的画卷。
#include <iostream>  

#include <cstdio>  

#include <algorithm>  

#include <vector>

#include <cstring>

#define lowbit(x) (x&(-x)) 

#define LL long long 

using namespace std;  

const int N = 50005;  

struct Point{  

    int x,y,id;  

    bool operator<(const Point p)const{  

        return x!=p.x?x<p.x:y<p.y;  

    }  

}p[N],pp[N];  

//数状数组,找(y-x)大于以后的,但是y+x最小的

struct BIT{  

    int min_val,pos;  

    void init(){  

        min_val=(1<<30);  

        pos=-1;  

    }  

}bit[N];  

//全部效有边,Kruskal

struct Edge{  

    int u,v,d;  

    bool operator<(const Edge e)const{  

        return d<e.d;  

    }  

}e[N<<2];  

//前向星

struct Graph{

    int v,next;

}edge[N<<1];

int n,m,tot,pre[N];  

int total,start[N];

int find(int x){  

    return pre[x]=(x==pre[x]?x:find(pre[x]));  

}  

inline int dist(int i,int j){  

    return abs(p[i].x-p[j].x)+abs(p[i].y-p[j].y);  

}  

inline void addedge(int u,int v,int d){  

    e[tot].u=u;  

    e[tot].v=v;  

    e[tot++].d=d;  

}  

inline void _add(int u,int v){

    edge[total].v=v;

    edge[total].next=start[u];

    start[u]=total++;

}

inline void update(int x,int val,int pos){  

    for(int i=x;i>=1;i-=lowbit(i))  

        if(val<bit[i].min_val)  

            bit[i].min_val=val,bit[i].pos=pos;  

}  

inline int ask(int x,int m){  

    int min_val=(1<<30),pos=-1;  

    for(int i=x;i<=m;i+=lowbit(i))  

        if(bit[i].min_val<min_val)  

            min_val=bit[i].min_val,pos=bit[i].pos;  

    return pos;  

}  

inline void Manhattan_minimum_spanning_tree(int n,Point *p){  

    int a[N],b[N];  

    for(int dir=0;dir<4;dir++){  

        //4种坐标换变  

        if(dir==1||dir==3){  

            for(int i=0;i<n;i++)  

                swap(p[i].x,p[i].y);  

        }  

        else if(dir==2){  

            for(int i=0;i<n;i++){  

                p[i].x=-p[i].x;  

            }  

        }  

        sort(p,p+n);  

        for(int i=0;i<n;i++){  

            a[i]=b[i]=p[i].y-p[i].x;  

        }  

        sort(b,b+n);  

        int m=unique(b,b+n)-b;  

        for(int i=1;i<=m;i++)  

            bit[i].init();  

        for(int i=n-1;i>=0;i--){  

            int pos=lower_bound(b,b+m,a[i])-b+1;   //BIT中从1开始  

            int ans=ask(pos,m);  

            if(ans!=-1)  

                addedge(p[i].id,p[ans].id,dist(i,ans));  

            update(pos,p[i].x+p[i].y,i);  

        }  

    }  

    sort(e,e+tot);  

    for(int i=0;i<n;i++)  

        pre[i]=i;  

    for(int i=0;i<tot;i++){  

        int u=e[i].u,v=e[i].v;  

        int fa=find(u),fb=find(v);  

        if(fa!=fb){ 

            pre[fa]=fb;  

            _add(u,v);

            _add(v,u);

        }  

    }  

}  

LL gcd(LL a,LL b){

    return b==0?a:gcd(b,a%b);

}

LL up[N],down[N];

LL ans;

int col[N],vis[N]={0};

int cnt[N]={0};   //记载每种色颜涌现的次数

inline void add(int l,int r){

    for(int i=l;i<=r;i++){

        int c=col[i];

        ans-=(LL)cnt[c]*(cnt[c]-1)/2;

        cnt[c]++;

        ans+=(LL)cnt[c]*(cnt[c]-1)/2;

    }

}

inline void del(int l,int r){

    for(int i=l;i<=r;i++){

        int c=col[i];

        ans-=(LL)cnt[c]*(cnt[c]-1)/2;

        cnt[c]--;

        ans+=(LL)cnt[c]*(cnt[c]-1)/2;

    }

}

//[l1,r1]前一个区间 [l2,r2]以后区间

void dfs(int l1,int r1,int l2,int r2,int idx,int pre){  



    if(l2<l1) add(l2,l1-1);

    if(r2>r1) add(r1+1,r2);

    if(l2>l1) del(l1,l2-1);

    if(r2<r1) del(r2+1,r1);

    up[pp[idx].id]=ans;

    vis[idx]=1;

    for(int i=start[idx];i!=-1;i=edge[i].next){

        int v=edge[i].v;

        if(vis[v]) continue;

        dfs(l2,r2,pp[v].x,pp[v].y,v,idx);

    }

    if(l2<l1) del(l2,l1-1);

    if(r2>r1) del(r1+1,r2);

    if(l2>l1) add(l1,l2-1);

    if(r2<r1) add(r2+1,r1);

}

int main(){  

    //freopen("input.txt","r",stdin);

    scanf("%d%d",&n,&m);  

    tot=total=0;

    memset(start,-1,sizeof(start));  

    for(int i=1;i<=n;i++)

        scanf("%d",&col[i]);

    for(int i=0;i<m;i++){  

        scanf("%d%d",&p[i].x,&p[i].y);  

        down[i]=(LL)(p[i].y-p[i].x+1)*(p[i].y-p[i].x)/2;

        p[i].id=i;  

        pp[i]=p[i];   //本副一份,便于面后DFS,或者之后按id序排

    } 

    Manhattan_minimum_spanning_tree(m,p);

    for(int i=0;i<m;i++){

        p[i].y=-p[i].y;

    }

    dfs(2,1,pp[0].x,pp[0].y,0,-1);

    for(int i=0;i<m;i++){

        LL g=gcd(up[i],down[i]);

        printf("%lld/%lld\n",up[i]/g,down[i]/g);

    }

    return 0;  

}  


文章结束给大家分享下程序员的一些笑话语录:  一边用着越狱的ip,一边拜乔帮主的果粉自以为是果粉,其实在乔帮主的眼里是不折不扣的叛徒。

你可能感兴趣的:(OS)