hdu 5861 (線段樹,區間更新,單點查詢)

There are n villages along a high way, and divided the high way into n-1 segments. Each segment would charge a certain amount of money for being open for one day, and you can open or close an arbitrary segment in an arbitrary day, but you can open or close the segment for just one time, because the workers would be angry if you told them to work multiple period.

We know the transport plan in the next m days, each day there is one cargo need to transport from village aiai to village bibi, and you need to guarantee that the segments between aiai and bibi are open in the i-th day. Your boss wants to minimize the total cost of the next m days, and you need to tell him the charge for each day.

(At the beginning, all the segments are closed.)
Input
Multiple test case. For each test case, begins with two integers n, m(1<=n,m<=200000), next line contains n-1 integers. The i-th integer wiwi(1<=wiwi<=1000) indicates the charge for the segment between village i and village i+1 being open for one day. Next m lines, each line contains two integers ai,bi(1≤ai,bi<=n,ai!=bi)ai,bi(1≤ai,bi<=n,ai!=bi).
Output
For each test case, output m lines, each line contains the charge for the i-th day.
Sample Input
4 3
1 2 3
1 3
3 4
2 4
Sample Output
3
5
5

知道是線段樹後自己做出來的,哈哈哈,好開心呀,還有個蜜汁坑點= =,我這都找出來了。。出題人坑這個真無聊了 詢問的L還有可能比R大
算一個自己以後用的板子吧
就是先統計出每一段路會出現在哪幾天,保留最大最小值;
就是建兩課線段樹,第一棵是爲了求線段樹的最早出現和最晚出現
第二棵是下標是哪一天的id,更新就用 每一段路來進行更新,無敵優美

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
int a[N],sum[N*4];
int laz[N*4];
int minn[N*4],maxx[N*4];
void push_down(int rt,int m)
{
    sum[rt<<1]+=laz[rt]*(m-(m>>1));
    sum[rt<<1|1]+=laz[rt]*(m>>1);
    laz[rt<<1]+=laz[rt];
    laz[rt<<1|1]+=laz[rt];
    laz[rt]=0;
}

int n,m;
void push_down2(int rt)
{
    maxx[rt<<1]=max(maxx[rt<<1],maxx[rt]);
    minn[rt<<1]=min(minn[rt<<1],minn[rt]);
    maxx[rt<<1|1]=max(maxx[rt<<1|1],maxx[rt]);
    minn[rt<<1|1]=min(minn[rt<<1|1],minn[rt]);
}

void update(int L,int R,int l,int r,int rt,int add)
{
    if(L<=l&&R>=r){
        sum[rt]+=(r-l+1)*add;
        laz[rt]+=add;
        return ;
    }
    if(laz[rt])
        push_down(rt,r-l+1);
    int mid=(l+r)>>1;
    if(L<=mid) update(L,R,l,mid,rt<<1,add);
    if(R>mid) update(L,R,mid+1,r,rt<<1|1,add);
}

void build(int l,int r,int rt)
{
    if(l==r)
    {
        if(minn[rt]<=maxx[rt])
            update(minn[rt],maxx[rt],1,m,1,a[l]);
        return ;
    }
    push_down2(rt);
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
}

void update2(int l,int r,int L,int R,int rt,int id)
{
    if(L<=l&&R>=r){
        maxx[rt]=max(maxx[rt],id);
        minn[rt]=min(minn[rt],id);
        return ;
    }
    push_down2(rt);
    int mid=(l+r)>>1;
    if(L<=mid) update2(l,mid,L,R,rt<<1,id);
    if(R>mid) update2(mid+1,r,L,R,rt<<1|1,id);
}

int query(int l,int r,int d,int rt)
{
    if(l==r&&l==d)
        return sum[rt];
    if(laz[rt])
        push_down(rt,r-l+1);
    int mid=(l+r)>>1;
    if(d<=mid) return query(l,mid,d,rt<<1);
    else return query(mid+1,r,d,rt<<1|1);
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(sum,0,sizeof(sum));
        memset(minn,0x3f,sizeof(minn));
        memset(maxx,0,sizeof(maxx));
        memset(laz,0,sizeof(laz));
        n--;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)
        {
            int L,R;
            scanf("%d%d",&L,&R);
            if(L>R) swap(L,R);
            update2(1,n,L,R-1,1,i);
        }

        build(1,n,1);

        for(int i=1;i<=m;i++)
            printf("%d\n",query(1,m,i,1) );
    }
}
發佈了60 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章