zoukankan      html  css  js  c++  java
  • 4826: [Hnoi2017]影魔

    4826: [Hnoi2017]影魔

    https://lydsy.com/JudgeOnline/problem.php?id=4826

    分析:

      莫队+单调栈+st表。

      考虑如何O(1)加入一个点,删除一个点,类似bzoj4540。然后就可以莫队了。复杂度$O(nsqrt n)$

    代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #include<map>
    11 using namespace std;
    12 typedef long long LL;
    13 
    14 char buf[100000], *p1 = buf, *p2 = buf;
    15 #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    16 inline int read() {
    17     int x=0,f=1;char ch=nc();for(;!isdigit(ch);ch=nc())if(ch=='-')f=-1;
    18     for(;isdigit(ch);ch=nc())x=x*10+ch-'0';return x*f;
    19 }
    20 
    21 const int N = 200005;
    22 struct Edge{
    23     int l, r, bel, id;
    24     bool operator < (const Edge &A) const {
    25         return bel == A.bel ? r < A.r : bel < A.bel;
    26     }
    27 }Q[N];
    28 int cnt[N], a[N], f[N][22], Log[N];
    29 int sum1R[N], sum1L[N], sum2R[N], sum2L[N], q[N], mxL[N], mxR[N];
    30 int P1, P2, L, R, n, m;
    31 LL ans[N], Ans = 0;
    32 
    33 int getmax(int l,int r) {
    34     int k = Log[r - l + 1];
    35     int p1 = f[l][k], p2 = f[r - (1 << k) + 1][k];
    36     return a[p1] > a[p2] ? p1 : p2;
    37 }
    38 
    39 void updR(int x,int f) {
    40     if (L >= R) { Ans = 0; return ; }
    41     int p = getmax(L, R - 1), p2 = max(mxL[x], p);
    42     Ans += (sum1L[R - 1] - sum1L[p2] + 1) * P1 * f;
    43     Ans += (sum1L[p2] - sum1L[p]) * P2 * f;
    44     Ans += (sum2L[R - 1] - sum2L[p2]) * P2 * f;
    45     if (L > mxL[x]) Ans += (p2 - L) * P2 * f;
    46 }
    47 
    48 void updL(int x,int f) {
    49     if (L >= R) { Ans = 0; return ; }
    50     int p = getmax(L + 1, R), p2 = min(mxR[x], p);
    51     Ans += (sum1R[L + 1] - sum1R[p2] + 1) * P1 * f;
    52     Ans += (sum1R[p2] - sum1R[p]) * P2 * f;
    53     Ans += (sum2R[L + 1] - sum2R[p2]) * P2 * f;
    54     if (R < mxR[x]) Ans += (R - p2) * P2 * f;
    55 }
    56 
    57 int main() {
    58     n = read(), m = read();P1 = read(), P2 = read(); 
    59     int B = sqrt(n);
    60     for (int i = 1; i <= n; ++i) a[i] = read(), f[i][0] = i;
    61     for (int j = 1; (1 << j) <= n; ++j) {
    62         for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
    63             int p1 = f[i][j - 1], p2 = f[i + (1 << (j - 1))][j - 1];
    64             f[i][j] = a[p1] > a[p2] ? p1 : p2;
    65         }
    66     }
    67     Log[0] = -1;
    68     for (int i = 1; i <= n; ++i) Log[i] = Log[i >> 1] + 1;
    69     a[0] = a[n + 1] = 1e9;
    70     int l = 1, r = 1; q[1] = 0;
    71     for (int i = 1; i <= n; ++i) {
    72         while (l <= r && a[i] > a[q[r]]) r --;
    73         q[++r] = i;
    74         int j = q[r - 1]; mxL[i] = j;        
    75         sum2L[i] = sum2L[j] + (i - j - 1); sum1L[i] = sum1L[j] + 1;
    76     }
    77     l = 1, r = 1; q[1] = n + 1;
    78     for (int i = n; i >= 1; --i) {
    79         while (l <= r && a[i] > a[q[r]]) r --;
    80         q[++r] = i;
    81         int j = q[r - 1]; mxR[i] = j;
    82         sum2R[i] = sum2R[j] + (j - i - 1); sum1R[i] = sum1R[j] + 1;
    83     }
    84     for (int i = 1; i <= m; ++i) {
    85         Q[i].l = read(), Q[i].r = read(), Q[i].bel = (Q[i].l - 1) / B + 1, Q[i].id = i;
    86     }
    87     sort(Q + 1, Q + m + 1);
    88     L = 1, R = 0;
    89     for (int i = 1; i <= m; ++i) {
    90         while (L > Q[i].l) L --, updL(L, 1);
    91         while (R < Q[i].r) R ++, updR(R, 1);
    92         while (L < Q[i].l) updL(L, -1), L ++;
    93         while (R > Q[i].r) updR(R, -1), R --;
    94         ans[Q[i].id] = Ans;
    95     }
    96     for (int i = 1; i <= m; ++i) printf("%lld
    ", ans[i]);
    97     return 0;
    98 }
    View Code

    sol2:

      每个点i找到左边右边第一个比它大的点,设为x,y,那么x,y会产生P1的贡献,x和[i+1,y-1],y和[x+1,i-1]会产生P2的贡献,把它们看做是平面上的点,然后转化为二维数点问题。

      询问区间L,R,就是询问横坐标在[L,R]的,纵坐标也在[L,R]的点有多少个。有一个问题:(y,x+1)这个点是否和(x+1,y)的贡献一样?就是这两个数哪个在前面的问题,因为询问总是一个关于直线y=x对称的一个矩形,而(y,x+1)和(x+1,y)也关于y=x对称,所以这两个点怎么放都行。

      然后离线+扫描线+线段树就行了(可以标记永久化)。复杂度$O(nlogn)$

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<set>
     8 #include<queue>
     9 #include<vector>
    10 #include<map>
    11 #define Root 1, n,  1
    12 #define lson l, mid, rt << 1
    13 #define rson mid + 1, r, rt << 1 | 1
    14 using namespace std;
    15 typedef long long LL;
    16 
    17 inline int read() {
    18     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    19     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    20 }
    21 
    22 const int N = 200005;
    23 struct Node{
    24     int p, l, r, id, w;
    25     bool operator < (const Node &A) const { return p < A.p; }
    26 }q[N * 2], A[N * 3];
    27 int L[N], R[N], sk[N], a[N];
    28 LL sum[N << 2], tag[N << 2], ans[N];
    29 
    30 void update(int l,int r,int rt,int L,int R,int v) {
    31     sum[rt] += 1ll * (R - L + 1) * v;
    32     if (L == l && r == R) {
    33         tag[rt] += v; return ;
    34     }
    35     int mid = (l + r) >> 1;
    36     if (R <= mid) update(lson, L, R, v);
    37     else if (L > mid) update(rson, L, R, v);
    38     else update(lson, L, mid, v), update(rson, mid + 1, R, v);
    39 }
    40 LL query(int l,int r,int rt,int L,int R,LL t) {
    41     if (L == l && r == R) return sum[rt] + 1ll * (R - L + 1) * t;
    42     int mid = (l + r) >> 1;
    43     if (R <= mid) return query(lson, L, R, t + tag[rt]);
    44     else if (L > mid) return query(rson, L, R, t + tag[rt]);
    45     else return query(lson, L, mid, t + tag[rt]) + query(rson, mid + 1, R, t + tag[rt]);
    46 }
    47 int main() {
    48     int n = read(), m = read(), P1 = read(), P2 = read();
    49     for (int i = 1; i <= n; ++i) a[i] = read();
    50     for (int top = 0, i = 1; i <= n; ++i) {
    51         while (top && a[i] > a[sk[top]]) top --;
    52         sk[++top] = i;
    53         L[i] = sk[top - 1];
    54     }
    55     sk[0] = n + 1;
    56     for (int top = 0, i = n; i >= 1; --i) {
    57         while (top && a[i] > a[sk[top]]) top --;
    58         sk[++top] = i;
    59         R[i] = sk[top - 1];
    60     }
    61     int tot = 0; 
    62     for (int i = 1; i <= n; ++i) {
    63         if (L[i] && R[i] <= n) A[++tot] = (Node){R[i], L[i], L[i], 0, P1};
    64         if (L[i] && R[i] > i + 1) A[++tot] = (Node){L[i], i + 1, R[i] - 1, 0, P2};
    65         if (R[i] <= n && i > L[i] + 1) A[++tot] = (Node){R[i], L[i] + 1, i - 1, 0, P2};
    66     }
    67     for (int i = 1; i <= m; ++i) {
    68         int l = read(), r = read();
    69         q[i] = (Node){l - 1, l, r, i, -1};
    70         q[i + m] = (Node){r, l, r, i, 1};
    71         ans[i] += 1ll * (r - l) * P1;
    72     }
    73     sort(q + 1, q + m + m + 1);
    74     sort(A + 1, A + tot + 1);
    75     int now = 1;
    76     while (A[now].p <= 0) now ++;
    77     for (int i = 1; i <= m + m; ++i) {
    78         while (now <= tot && A[now].p <= q[i].p) {
    79             update(Root, A[now].l, A[now].r, A[now].w); now ++;
    80         }
    81         ans[q[i].id] += 1ll * query(Root, q[i].l, q[i].r, 0) * q[i].w;
    82     }
    83     for (int i = 1; i <= m; ++i) printf("%lld
    ", ans[i]);
    84     return 0;
    85 }
    View Code
  • 相关阅读:
    socket.io建立长连接
    编译性语言、解释性语言和脚本语言的区别
    回调函数
    jquery文档处理
    css--Bootstrap框架
    css--960框架
    html基础
    真的理解闭包了吗,用闭包的时候应该注意什么?
    初识reactJs 相关
    简单方便的div垂直居中。
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10072954.html
Copyright © 2011-2022 走看看