SHUOJ422解题报告【时间维度上的线段树】

题目地址:

  http://acmoj.shu.edu.cn/problem/422/

题目概述:

  给出一个区间,有两种操作:

  区间整体加(减)某一个数

  查询某个点的历史最大绝对值

大致思路:

  看了某大牛的解题报告之后才明白。

  大致意思就是我们维护一颗时间维度的线段树,但如果单纯这样的话对每个点都要这样一颗线段树内存是不够的,所以我们得将线段树合并一下。

  如果我们依次遍历每个点的话,实际上可以用一个类似前缀和的东西来维护当前点被加(减)了多少,这样只需要在遍历的过程中维护线段树然后回复这个点的所有查询就好了,而因为我们维护的线段树是时间维度的,所以这件事情是可做的。

  可能我讲的不是很清楚,具体可以看代码。

复杂度分析:

  建树是O(qlogq),查询修改是O(logq),然后遍历所有点就是O(nlogq),综合起来就是O(nlogn)。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <ctime>
#include <map>
#include <assert.h>
#include <stack>
#include <set>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;

#define sacnf scanf
#define scnaf scanf
#define maxn 100010
#define maxm 20010
#define inf 1061109567
#define INF 0x3f3f3f3f
#define Eps 0.000001
const double PI=acos(-1.0);
#define mod 1000000007
#define MAXNUM 10000
#define For(i,j,k) for(int (i)=(j);(i)<=(k);(i)++)
#define mes(a,b) memset((a),(b),sizeof(a))
#define scanfi(a) scanf("%d",&(a))
typedef long long ll;
typedef unsigned long long ulld;
void Swap(int &a,int &b) {int t=a;a=b;b=t;}
ll Abs(ll x) {return (x<0)?-x:x;}

struct node
{
    int Max,Min,Add;
} tree[maxn*4];

vector<node> pre[maxn];
vector<int> q[maxn];
int a[maxn],ans[maxn];

void build_tree(int l,int r,int dir)
{
    tree[dir].Max=tree[dir].Min=tree[dir].Add=0;
    if(l==r) return;
    int m=(l+r)>>1;
    build_tree(l,m,dir*2);
    build_tree(m+1,r,dir*2+1);
}

void addin(int dir,int val)
{
    tree[dir].Add+=val;
    tree[dir].Max+=val;
    tree[dir].Min+=val;
}

void push_down(int dir)
{
    if(tree[dir].Add!=0)
    {
        addin(dir*2,tree[dir].Add);
        addin(dir*2+1,tree[dir].Add);
        tree[dir].Add=0;
    }
}

void maintain(int dir)
{
    tree[dir].Max=max(tree[dir*2].Max,tree[dir*2+1].Max);
    tree[dir].Min=min(tree[dir*2].Min,tree[dir*2+1].Min);
}

void add(int l,int r,int dir,int al,int ar,int x)
{
    if(r<al||ar<r) return;
    if(al<=l&&r<=ar)
    {
        addin(dir,x);
        return;
    }
    push_down(dir);
    int m=(l+r)>>1;
    add(l,m,dir*2,al,ar,x);
    add(m+1,r,dir*2+1,al,ar,x);
    maintain(dir);
}

node query(int l,int r,int dir,int ql,int qr)
{
    if(r<ql||qr<l) return (node){-inf,inf,0};
    if(ql<=l&&r<=qr) return tree[dir];
    push_down(dir);
    int m=(l+r)>>1;node t1,t2;
    t1=query(l,m,dir*2,ql,qr);
    t2=query(m+1,r,dir*2+1,ql,qr);
    maintain(dir);
    return (node){max(t1.Max,t2.Max),min(t1.Min,t2.Min)};
}

int main()
{
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    //clock_t st=clock();
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,Q;scanf("%d%d",&n,&Q);pre[n+1].clear();
        For(i,1,n) scanfi(a[i]),pre[i].clear(),q[i].clear();
        int opt,l,r,x;
        For(i,1,Q)
        {
            scanfi(opt);
            if(opt==1)
            {
                scanf("%d%d%d",&l,&r,&x);
                pre[l].push_back((node){i,x,0});
                pre[r+1].push_back((node){i,-x,0});
            }
            else if(opt==2)
            {
                scanfi(x);q[x].push_back(i);
            }
        }
        build_tree(1,Q,1);
        mes(ans,0x3f);
        For(i,1,n)
        {
            int len=pre[i].size();
            For(j,0,len-1)
            {
                node t=pre[i][j];
                add(1,Q,1,t.Max,Q,t.Min);
            }
            len=q[i].size();
            For(j,0,len-1)
            {
                int t=q[i][j];
                node tmp=query(1,Q,1,1,t);
                ans[t]=max(abs(a[i]+tmp.Max),abs(a[i]+tmp.Min));
                ans[t]=max(ans[t],abs(a[i]));
            }
        }
        For(i,1,Q)
            if(ans[i]!=inf) printf("%d
",ans[i]);
    }
    //clock_t ed=clock();
    //printf("

Time Used : %.5lf Ms.
",(double)(ed-st)/CLOCKS_PER_SEC);
    return 0;
}
原文地址:https://www.cnblogs.com/CtrlKismet/p/7168852.html