数据结构

void init()
{
    for(int i = 1;i <= n;i++)    pre[i] = i;
} 

int findd(int x)       递归     
{
    return pre[x] == x?x:pre[x] = findd(pre[x]);
}

void join(int a,int b)
{
    int x = findd(a),y = findd(b);
    if(x != y)  pre[x] = y;
}    
并查集
#include <stdio.h>
const int N = 50005;
int pre[N],rk[N];
/*
    解题思路:father[y] = x
    如果rank[y]为0 代表x 和 y属于同一种
    如果rank[y]为1 代表x 吃 y
    如果rank[y]为2 代表y 吃 x
    本题的关键就是如何在路径压缩的过程中更新关系权值
    需要总结更新公式
*/
int findd(int x)
{
    if(pre[x] == x) return x;
    int xx = findd(pre[x]);
    rk[x] = (rk[x]+rk[pre[x]])%3;
    pre[x] = xx;
    return xx;
}
bool ok(int n,int type,int x,int y)
{
    if(x > n || y > n)  return 0;
    int fx = findd(x),fy = findd(y);
    if(fx == fy)
    {
        if((rk[y]-rk[x]+3)%3 != type-1) return 0;
        return 1;
    }
    else
    {
        pre[fy] = fx;
        rk[fy] = (rk[x]-rk[y]+type-1+3)%3;
        return 1;
    }
}

int main()
{
    int n,k;
    scanf("%d %d",&n,&k);
    for(int i = 1;i <= n;i++)
    {
        pre[i] = i;
        rk[i] = 0;
    }
    int cnt = 0;
    for(int i = 0;i < k;i++)
    {
        int d,x,y;
        scanf("%d %d %d",&d,&x,&y);
        if(!ok(n,d,x,y))    cnt++;
    }
    printf("%d\n",cnt);
    return 0;
}
带权值并查集

struct ST
{
    int mm[100005],dp[100005][20];
    void init()
    {
        mm[0] = -1;
        for(int i = 1;i <= n;i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = a[i];
        }
        for(int j = 1;j <= mm[n];j++)
        {
            for(int i = 1;i+(1<<j)-1 <= n;i++)  dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
    int query(int a,int b)
    {
        if(a > b)   swap(a,b);
        int k = mm[b-a+1];
        return min(dp[a][k],dp[b-(1<<k)+1][k]);
    }
}st;
一维rmq
//同一维一样 用dp[row][col][i][j]表示(row,col)到(row+2^i,col+2^j)矩形内的最小值
int a[305][305],mm[305],dp[305][305][9][9];

void init(int n,int m)
{
    for(int i = 1;i <= 300;i++) mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)   dp[i][j][0][0] = a[i][j];
    }
    for(int i = 0;i <= mm[n];i++)
    {
        for(int j = 0;j <= mm[m];j++)
        {
            if(i==0 && j==0)    continue;
            for(int row = 1;row+(1<<i)-1 <= n;row++)
            {
                for(int col = 1;col+(1<<j)-1 <= m;col++)
                {
                    if(i)   dp[row][col][i][j]  = max(dp[row][col][i-1][j],dp[row+(1<<(i-1))][col][i-1][j]);
                    else    dp[row][col][i][j]  = max(dp[row][col][i][j-1],dp[row][col+(1<<(j-1))][i][j-1]);
                }
            }
        }
    }
}
int rmq(int x1,int y1,int x2,int y2)
{
    int k1 = mm[x2-x1+1],k2 = mm[y2-y1+1];
    x2 = x2-(1<<k1)+1,y2 = y2-(1<<k2)+1;
    return max(max(dp[x1][y1][k1][k2],dp[x1][y2][k1][k2]),max(dp[x2][y1][k1][k2],dp[x2][y2][k1][k2]));
}
二维rmq

#include<bits/stdc++.h>
using namespace std;

stack<long long> s;
long long a[100005];
int main()
{
    int n;
    while(scanf("%d",&n) && n)
    {
        while(!s.empty())   s.pop();
        long long ans = 0;
        for(int i = 1;i <= n;i++)   scanf("%lld",&a[i]);
        a[n+1] = 0;
        for(int i = 1;i <= n+1;i++)
        {
            while(!s.empty() && a[s.top()] > a[i])
            {
                int temp = s.top();
                s.pop();
                int len = s.empty()?i-1:i-s.top()-1;
                ans = max(ans,len*a[temp]);
            }
            s.push(i);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

//HDU1506
单调栈
#include<bits/stdc++.h>
using namespace std;

struct st
{
    int num,t;
}s;
deque<st> q;
int n,x;

int main()
{
    while(~scanf("%d",&n))
    {
        while(!q.empty())   q.pop_back();
        int out = 1,cnt = 1;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&x);
            switch(x)
            {
                case 1:
                    int tt;
                    scanf("%d",&tt);
                    s.t = tt-i;
                    s.num = cnt++;
                    while(!q.empty() && q.back().t <= s.t)    q.pop_back();
                    q.push_back(s);
                    break;
                case 2:
                    if(q.front().num == out++)  q.pop_front();
                    break;
                case 3:
                    printf("%d\n",q.front().t+i);
            }
        }
    }
    return 0;
}

//XDOJ1156
单调队列

int tree[50005],n;

inline int lowbit(int x)
{
    return x & (-x);
}

void update(int pos,int x)
{
    while(pos <= n)
    {
        tree[pos] += x;
        pos += lowbit(pos);
    }
}

int getsum(int pos)
{
    int sum = 0;
    while(pos > 0)
    {
        sum += tree[pos];
        pos -= lowbit(pos);
    }
    return sum;
}
一维树状数组
int tree[1005][1005] = {0},a[1005][1005] = {0};

int lowbit(int x)
{
    return x&(-x);
}

void update(int x,int y,int w)
{
    for(int i = x;i <= 1001;i += lowbit(i))
    {
        for(int j = y;j <= 1001;j += lowbit(j)) tree[i][j] += w;
    }
}

int getsum(int x,int y)
{
    int ans = 0;
    for(int i = x;i > 0;i -= lowbit(i))
    {
        for(int j = y;j > 0;j -= lowbit(j)) ans += tree[i][j];
    }
    return ans;
}
二维树状数组

#include<bits/stdc++.h>
using namespace std;
#define N 100005

int n,m,tree[20][N],sorted[N],toleft[20][N];

void build(int l,int r,int dep)
{
    if(l == r)return;
    int mid = (l+r)/2,same = mid-l+1;
    for(int i = l;i <= r;i++)
    {
        if(tree[dep][i] < sorted[mid])  same--;
    }
    int lpos = l,rpos = mid+1;
    for(int i = l;i <= r;i++)
    {
        if(tree[dep][i] < sorted[mid])  tree[dep+1][lpos++] = tree[dep][i];
        else if(tree[dep][i] == sorted[mid] && same > 0)
        {
            tree[dep+1][lpos++] = tree[dep][i];
            same--;
        }
        else    tree[dep+1][rpos++] = tree[dep][i];
        toleft[dep][i] = toleft[dep][l-1]+lpos-l;
    }
    build(l,mid,dep+1);
    build(mid+1,r,dep+1);
}

int query(int l,int r,int ql,int qr,int dep,int k)
{
    if(ql == qr)    return tree[dep][ql];
    int mid = (l+r)/2,cnt = toleft[dep][qr]-toleft[dep][ql-1];
    if(cnt >= k)
    {
        int ll = l+toleft[dep][ql-1]-toleft[dep][l-1],rr = ll+cnt-1;
        return query(l,mid,ll,rr,dep+1,k);
    }
    else
    {
        int rr = qr+toleft[dep][r]-toleft[dep][qr],ll = rr-(qr-ql-cnt);
        return query(mid+1,r,ll,rr,dep+1,k-cnt);
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&tree[0][i]);
            sorted[i] = tree[0][i];
        }
        sort(sorted+1,sorted+n+1);
        build(1,n,0);
        while(m--)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",query(1,n,l,r,0,k));
        }
    }
    return 0;
}
划分树查询区间第k大

int n,k,root,son[10005],vis[10005],minn,ans,sum,dis[10005],dep[10005];
struct xx
{
    int to,w;
    xx(int a,int b):to(a),w(b){};
};
vector<xx> v[10005];

void dfsroot(int now,int pre)
{
    son[now] = 1;
    int maxx = 0;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i].to,w = v[now][i].w;
        if(t == pre || vis[t])  continue;
        dfsroot(t,now);
        son[now] += son[t];
        maxx = max(maxx,son[t]);
    }
    maxx = max(maxx,sum-son[now]);
    if(maxx < minn)
    {
        minn = maxx;
        root = now;
    }
}

void dfsdep(int now,int pre)
{
    dep[++dep[0]] = dis[now];
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i].to,w = v[now][i].w;
        if(t == pre || vis[t])  continue;
        dis[t] = dis[now]+w;
        dfsdep(t,now);
    }
}

int calc(int now,int w)
{
    dis[now] = w;
    dep[0] = 0;
    dfsdep(now,0);
    sort(dep+1,dep+dep[0]+1);
    int l = 1,r = dep[0],cnt = 0;
    while(l < r)
    {
        if(dep[l]+dep[r] <= k)
        {
            cnt += r-l;
            l++;
        }
        else    r--;
    }
    return cnt;
}

void solve(int now)
{
    ans += calc(now,0);
    vis[now] = 1;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i].to,w = v[now][i].w;
        if(vis[t])  continue;
        ans -= calc(t,w);
        minn = 1e9;
        sum = son[t];
        dfsroot(t,0);
        solve(root);
    }
}

int main()
{
    while(scanf("%d%d",&n,&k))
    {
        if(n == 0 || k == 0)    break;
        ans = 0,sum = n;
        memset(vis,0,sizeof(vis));
        for(int i = 1;i <= n;i++)   v[i].clear();
        for(int i = 1;i < n;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            v[x].push_back(xx(y,z));
            v[y].push_back(xx(x,z));
        }
        minn = 1e9;
        dfsroot(1,0);
        solve(root);
        printf("%d\n",ans);
    }
    return 0;
}
点分治求边权和等于k的数量
int n,k,root,son[100005],vis[100005],dep[100005],id[1000005],minn,ans1,ans2,sum;
long long a[100005],inv[1000005],mp[1000005];
vector<int> v[100005];

void dfsroot(int now,int pre)
{
    son[now] = 1;
    int maxx = 0;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t == pre || vis[t])  continue;
        dfsroot(t,now);
        son[now] += son[t];
        maxx = max(maxx,son[t]);
    }
    maxx = max(maxx,sum-son[now]);
    if(maxx < minn)
    {
        minn = maxx;
        root = now;
    }
}

void dfsdep(int now,int pre,long long x)
{
    dep[++dep[0]] = x*a[now]%MOD;
    id[dep[0]] = now;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t == pre || vis[t])  continue;
        dfsdep(t,now,x*a[now]%MOD);
    }
}

void update(int now,int x,int y)
{
    int t = mp[inv[x*a[now]%MOD]*k%MOD];
    if(!t)  return;
    if(t > y)   swap(t,y);
    if(t < ans1 || t == ans1 && y < ans2)
    {
        ans1 = t;
        ans2 = y;
    }
}

void solve(int now)
{
    vis[now] = 1;
    mp[1] = now;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(vis[t])  continue;
        dep[0] = 0;
        dfsdep(t,now,1);
        for(int j = 1;j <= dep[0];j++)  update(now,dep[j],id[j]);
        for(int j = 1;j <= dep[0];j++)
        {
            if(!mp[dep[j]] || mp[dep[j]] > id[j])   mp[dep[j]] = id[j];
        }
    }
    mp[1] = 0;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(vis[t])  continue;
        dep[0] = 0;
        dfsdep(t,now,1);
        for(int j = 1;j <= dep[0];j++)  mp[dep[j]] = 0;
    }
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(vis[t])  continue;
        minn = 1e9;
        sum = son[t];
        dfsroot(t,0);
        solve(root);
    }
}

int main()
{
    inv[1] = 1;
    for(int i = 2;i < MOD;i++)  inv[i] = (MOD-MOD/i)*inv[MOD%i]%MOD;
    while(~scanf("%d%d",&n,&k))
    {
        ans1 = 1e9,ans2 = 0;
        memset(vis,0,sizeof(vis));
        for(int i = 1;i <= n;i++)   v[i].clear();
        for(int i = 1;i <= n;i++)   scanf("%lld",&a[i]);
        for(int i = 1;i < n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        minn = 1e9;
        sum = n;
        dfsroot(1,0);
        solve(root);
        if(ans1 == 1e9) printf("No solution\n");
        else    printf("%d %d\n",ans1,ans2);
    }
    return 0;
}
点分治求点权积等于k

int n,maxx,tree[100005],ans[100005];
struct xx
{
    int x,y,z,id;
    xx(int a,int b,int c,int d):x(a),y(b),z(c),id(d){};
    xx(){};
}a[100005],b[100005];

inline lowbit(int x)
{
    return x&-x;
}

void add(int pos,int x)
{
    while(pos <= maxx)
    {
        tree[pos] += x;
        pos += lowbit(pos);
    }
}

int getsum(int pos)
{
    int ans = 0;
    while(pos > 0)
    {
        ans += tree[pos];
        pos -= lowbit(pos);
    }
    return ans;
}

bool cmp1(xx a,xx b)
{
    if(a.x != b.x)  return a.x < b.x;
    if(a.y != b.y)  return a.y < b.y;
    return a.z < b.z;
}

bool cmp2(xx a,xx b)
{
    if(a.y != b.y)  return a.y < b.y;
    return a.id < b.id;
}

void cdq(int l,int r)
{
    if(l == r)  return;
    int mid = (l+r)/2;
    int cnt = 0;
    for(int i = l;i <= mid;i++) b[++cnt] = xx(0,a[i].y,a[i].z,0);
    for(int i = mid+1;i <= r;i++)   b[++cnt] = xx(0,a[i].y,a[i].z,a[i].id);
    sort(b+1,b+1+cnt,cmp2);
    for(int i = 1;i <= cnt;i++)
    {
        if(b[i].id == 0)    add(b[i].z,1);
        else    ans[b[i].id] += getsum(b[i].z);
    }
    for(int i = 1;i <= cnt;i++)
    {
        if(b[i].id == 0)    add(b[i].z,-1);
    }
    cdq(l,mid);
    cdq(mid+1,r);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        maxx = 0;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
            a[i].id = i;
            maxx = max(maxx,a[i].z);
        }
        sort(a+1,a+1+n,cmp1);
        memset(ans,0,sizeof(ans));
        int cnt = 0;
        for(int i = n-1;i >= 1;i--)
        {
            if(a[i].x == a[i+1].x && a[i].y == a[i+1].y && a[i].z == a[i+1].z)  cnt++;
            else    cnt = 0;
            ans[a[i].id] += cnt;
        }
        cdq(1,n);
        for(int i = 1;i <= n;i++)   printf("%d\n",ans[i]);
    }
    return 0;
}
cdq分治求三维偏序

//点权,修改路径点权,查询单点权
#include<bits/stdc++.h>
using namespace std;
#define N 50005
int n,m,q,cnt,a[N],top[N],fa[N],dep[N],num[N],p[N],fp[N],son[N];
vector<int> v[N];
char s[10];

struct segtree
{
    int l,r;
    long long x,lazy;
}tree[4*N];

inline void pushup(int pos)
{
    tree[pos].x = tree[pos<<1].x+tree[pos<<1|1].x;
}

inline void pushdown(int pos)
{
    if(tree[pos].lazy)
    {
        tree[pos<<1].x += (tree[pos<<1].r-tree[pos<<1].l+1)*tree[pos].lazy;
        tree[pos<<1|1].x += (tree[pos<<1|1].r-tree[pos<<1|1].l+1)*tree[pos].lazy;
        tree[pos<<1].lazy += tree[pos].lazy;
        tree[pos<<1|1].lazy += tree[pos].lazy;
        tree[pos].lazy = 0;
    }
}

void build(int pos,int l,int r)
{
    tree[pos].l = l;
    tree[pos].r = r;
    tree[pos].lazy = 0;
    if(l == r)
    {
        tree[pos].x = a[fp[l]];
        return;
    }
    int mid = (l+r)/2;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}

void update(int pos,int l,int r,long long x)
{
    if(r < tree[pos].l || tree[pos].r < l)  return;
    if(l <= tree[pos].l && tree[pos].r <= r)
    {
        tree[pos].x += (tree[pos].r-tree[pos].l+1)*x;
        tree[pos].lazy += x;
        return;
    }
    pushdown(pos);
    update(pos<<1,l,r,x);
    update(pos<<1|1,l,r,x);
    pushup(pos);
}

long long getsum(int pos,int l,int r)
{
    if(r < tree[pos].l || tree[pos].r < l)  return 0;
    if(l <= tree[pos].l && tree[pos].r <= r)    return tree[pos].x;
    pushdown(pos);
    return  getsum(pos<<1,l,r)+getsum(pos<<1|1,l,r);
}

void dfs(int now,int pre,int d)
{
    dep[now] = d;
    fa[now] = pre;
    num[now] = 1;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t == pre)    continue;
        dfs(t,now,d+1);
        num[now] += num[t];
        if(son[now] == -1 || num[t] > num[son[now]])    son[now] = t;
    }
}

void getpos(int now,int sp)
{
    top[now] = sp;
    p[now] = ++cnt;
    fp[p[now]] = now;
    if(son[now] == -1)  return;
    getpos(son[now],sp);
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t != son[now] && t != fa[now])   getpos(t,t);
    }
}

void change(int u,int v,int x)
{
    int f1 = top[u],f2 = top[v];
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        update(1,p[f1],p[u],x);
        u = fa[f1];
        f1 = top[u];
    }
    if(dep[u] > dep[v]) swap(u,v);
    update(1,p[u],p[v],x);
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&q))
    {
        memset(son,-1,sizeof(son));
        memset(tree,0,sizeof(tree));
        for(int i = 1;i <= n;i++)   v[i].clear();
        cnt = 0;
        for(int i = 1;i <= n;i++)   scanf("%d",&a[i]);
        while(m--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        dfs(1,0,0);
        getpos(1,1);
        build(1,1,cnt);
        while(q--)
        {
            scanf("%s",s);
            if(s[0] == 'Q')
            {
                int x;
                scanf("%d",&x);
                printf("%lld\n",getsum(1,p[x],p[x]));
            }
            else
            {
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                if(s[0] == 'D')    z = -z;
                change(x,y,z);
            }
        }
    }
    return 0;
}
树链剖分线段树(点权)
#include<bits/stdc++.h>
#define N 10005
using namespace std;

int n,m,q,cnt,a[N],val[N],top[N],fa[N],dep[N],num[N],p[N],fp[N],son[N],e[N][3];
struct segtree
{
    int l,r,x;
}tree[4*N];
vector<int> v[N];
char s[10];

void pushup(int pos)
{
    tree[pos].x = max(tree[pos<<1].x,tree[pos<<1|1].x);
}

void build(int pos,int l,int r)
{
    tree[pos].l = l;
    tree[pos].r = r;
    if(l == r)
    {
        tree[pos].x = val[l];
        return;
    }
    int mid = (l+r)/2;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}

void update(int pos,int l,int r,int x)
{
    if(r < tree[pos].l || tree[pos].r < l)  return;
    if(l <= tree[pos].l && tree[pos].r <= r)
    {
        tree[pos].x = x;
        return;
    }
    update(pos<<1,l,r,x);
    update(pos<<1|1,l,r,x);
    pushup(pos);
}

int query(int pos,int l,int r)
{
    if(r < tree[pos].l || tree[pos].r < l)  return 0;
    if(l <= tree[pos].l && tree[pos].r <= r)    return tree[pos].x;
    return  max(query(pos<<1,l,r),query(pos<<1|1,l,r));
}

void dfs(int now,int pre,int d)
{
    dep[now] = d;
    fa[now] = pre;
    num[now] = 1;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t == pre)    continue;
        dfs(t,now,d+1);
        num[now] += num[t];
        if(son[now] == -1 || num[t] > num[son[now]])    son[now] = t;
    }
}

void getpos(int now,int sp)
{
    top[now] = sp;
    p[now] = ++cnt;
    fp[p[now]] = now;
    if(son[now] == -1)  return;
    getpos(son[now],sp);
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t != son[now] && t != fa[now])   getpos(t,t);
    }
}

int solve(int u,int v)
{
    int f1 = top[u],f2 = top[v],t = 0;
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        t = max(t,query(1,p[f1],p[u]));
        u = fa[f1];
        f1 = top[u];
    }
    if(u == v)  return t;
    if(dep[u] > dep[v]) swap(u,v);
    return max(t,query(1,p[son[u]],p[v]));
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(son,-1,sizeof(son));
        for(int i = 1;i <= n;i++)   v[i].clear();
        cnt = 0;
        for(int i = 1;i < n;i++)
        {
            scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]);
            v[e[i][0]].push_back(e[i][1]);
            v[e[i][1]].push_back(e[i][0]);
        }
        dfs(1,0,0);
        getpos(1,1);
        for(int i = 1;i < n;i++)
        {
            if(dep[e[i][0]] > dep[e[i][1]]) swap(e[i][0],e[i][1]);
            val[p[e[i][1]]] = e[i][2];
        }
        build(1,1,cnt);
        while(scanf("%s",s))
        {
            if(s[0] == 'D') break;
            int x,y;
            scanf("%d%d",&x,&y);
            if(s[0] == 'Q') printf("%d\n",solve(x,y));
            else    update(1,p[e[x][1]],p[e[x][1]],y);
        }
    }
    return 0;
}
树链剖分线段树(边权)

struct segtree
{
    int l,r;
    long long x,lazy;
}tree[400005];

inline void pushup(int pos)
{
    tree[pos].x = tree[pos<<1].x+tree[pos<<1|1].x;
}

inline void pushdown(int pos)
{
    if(tree[pos].lazy)
    {
        tree[pos<<1].x += (tree[pos<<1].r-tree[pos<<1].l+1)*tree[pos].lazy;
        tree[pos<<1|1].x += (tree[pos<<1|1].r-tree[pos<<1|1].l+1)*tree[pos].lazy;
        tree[pos<<1].lazy += tree[pos].lazy;
        tree[pos<<1|1].lazy += tree[pos].lazy;    
        tree[pos].lazy = 0;
    }
}

void build(int pos,int l,int r)   
{
    tree[pos].l = l;
    tree[pos].r = r;
    tree[pos].lazy = 0;
    if(l == r)
    {
        tree[pos].x = a[l];
        return;
    }
    int mid = (l+r)/2;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}

void update(int pos,int l,int r,long long x)
{
    if(r < tree[pos].l || tree[pos].r < l)  return;
    if(l <= tree[pos].l && tree[pos].r <= r)
    {
        tree[pos].x = (tree[pos].r-tree[pos].l+1)*x;
        tree[pos].lazy = x;
        return;
    }
    pushdown(pos);
    update(pos<<1,l,r,x);
    update(pos<<1|1,l,r,x);
    pushup(pos);
}

long long getsum(int pos,int l,int r)    
{
    if(r < tree[pos].l || tree[pos].r < l)  return 0;
    if(l <= tree[pos].l && tree[pos].r <= r)    return tree[pos].x;
    pushdown(pos);
    return  getsum(pos<<1,l,r)+getsum(pos<<1|1,l,r);
}
线段树模版
int n,k,q,cnt = 0,a[100005];
struct segtree
{
    int l,r,x,lazy;
    segtree *lson,*rson;
}*root;

segtree *newnode(int l,int r)
{
    segtree *t = new segtree;
    t->l = l;
    t->r = r;
    t->lson = NULL;
    t->rson = NULL;
    t->lazy = 0;
    t->x = a[l];
    return t;
}

segtree *newlson(segtree *pos)
{
    int mid = (pos->l+pos->r)/2;
    return newnode(pos->l,mid);
}

segtree *newrson(segtree *pos)
{
    int mid = (pos->l+pos->r)/2;
    return newnode(mid+1,pos->r);
}

void pushup(segtree *pos)
{
    if(!pos->lson)  pos->lson = newlson(pos);
    if(!pos->rson)  pos->rson = newrson(pos);
    pos->x = min(pos->lson->x,pos->rson->x);
}

void pushdown(segtree *pos)
{
    if(!pos->lson)  pos->lson = newlson(pos);
    if(!pos->rson)  pos->rson = newrson(pos);
    if(pos->lazy)
    {
        pos->lson->x = pos->lazy;
        pos->rson->x = pos->lazy;
        pos->lson->lazy = pos->lazy;
        pos->rson->lazy = pos->lazy;
        pos->lazy = 0;
    }
}

void update(segtree *pos,int l,int r,int x)
{
    if(r < pos->l || pos->r < l)    return;
    if(l <= pos->l && pos->r <= r)
    {
        pos->x = x;
        pos->lazy = x;
        return;
    }
    pushdown(pos);
    update(pos->lson,l,r,x);
    update(pos->rson,l,r,x);
    pushup(pos);
}

int getmin(segtree *pos,int l,int r)
{
    if(r < pos->l || pos->r < l)    return 1e9;
    if(l <= pos->l && pos->r <= r)  return pos->x;
    pushdown(pos);
    return min(getmin(pos->lson,l,r),getmin(pos->rson,l,r));
}
动态开点线段树
#include<bits/stdc++.h>
using namespace std;

int n,m;
long long a[100005];
struct segtree
{
    int l,r;
    long long x,sum;
}tree[400005];


inline void pushup(int pos)
{
    tree[pos].x = max(tree[pos<<1].x,tree[pos<<1|1].x);
    tree[pos].sum = tree[pos<<1].sum+tree[pos<<1|1].sum;
}

void build(int pos,int l,int r)
{
    tree[pos].l = l;
    tree[pos].r = r;
    if(l >= r)
    {
        tree[pos].x = a[l];
        tree[pos].sum = a[l];
        return;
    }
    int mid = (l+r)/2;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}

void edit(int pos,int l,int r,long long x,int t)
{
    if(t < l || t > r)  return;
    if(l == r)
    {
        tree[pos].x = x;
        tree[pos].sum = x;
        return;
    }
    int mid = (l+r)/2;
    edit(pos<<1,l,mid,x,t);
    edit(pos<<1|1,mid+1,r,x,t);
    pushup(pos);
}

void mod(int pos,int l,int r,long long x)
{
    if(r < tree[pos].l || tree[pos].r < l || tree[pos].x < x)   return;
    if(tree[pos].l == tree[pos].r)
    {
        tree[pos].x %= x;
        tree[pos].sum = tree[pos].x;
        return;
    }
    mod(pos<<1,l,r,x);
    mod(pos<<1|1,l,r,x);
    pushup(pos);
}

long long getsum(int pos,int l,int r)
{
    if(r < tree[pos].l || tree[pos].r < l)  return 0;
    if(l <= tree[pos].l && tree[pos].r <= r)    return tree[pos].sum;
    return  getsum(pos<<1,l,r)+getsum(pos<<1|1,l,r);
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 1;i <= n;i++)   cin >> a[i];
    build(1,1,n);
    for(int i = 1;i <= m;i++)
    {
        int z,l,r,x;
        cin >> z;
        if(z == 1)
        {
            cin >> l >> r;
            cout << getsum(1,l,r) << endl;
        }
        else if(z == 2)
        {
            cin >> l >> r >> x;
            mod(1,l,r,x);
        }
        else
        {
            cin >> l >> x;
            edit(1,1,n,x,l);
        }
    }
    return 0;
}
//CF438D
区间取模,单点修改,询问区间和
#include<bits/stdc++.h>
using namespace std;

int n,m;
long long a[100005];
struct segtree
{
    int l,r;
    long long ma,mi,sum,lazy;
}tree[400005];


inline void pushup(int pos)
{
    tree[pos].ma = max(tree[pos<<1].ma,tree[pos<<1|1].ma);
    tree[pos].mi = min(tree[pos<<1].mi,tree[pos<<1|1].mi);
    tree[pos].sum = tree[pos<<1].sum+tree[pos<<1|1].sum;
}

inline void pushdown(int pos)
{
    if(tree[pos].lazy)
    {
        long long t = tree[pos].lazy;
        tree[pos<<1].lazy += t;
        tree[pos<<1|1].lazy += t;
        tree[pos<<1].mi += t;
        tree[pos<<1|1].mi += t;
        tree[pos<<1].ma += t;
        tree[pos<<1|1].ma += t;
        tree[pos<<1].sum += (tree[pos<<1].r-tree[pos<<1].l+1)*t;
        tree[pos<<1|1].sum += (tree[pos<<1|1].r-tree[pos<<1|1].l+1)*t;
        tree[pos].lazy = 0;
    }
}

void build(int pos,int l,int r)
{
    tree[pos].l = l;
    tree[pos].r = r;
    tree[pos].lazy = 0;
    if(l == r)
    {
        tree[pos].mi = a[l];
        tree[pos].ma = a[l];
        tree[pos].sum = a[l];
        return;
    }
    int mid = (l+r)/2;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}

long long getsum(int pos,int l,int r)
{
    if(r < tree[pos].l || tree[pos].r < l)  return 0;
    if(l <= tree[pos].l && tree[pos].r <= r)    return tree[pos].sum;
    pushdown(pos);
    return  getsum(pos<<1,l,r)+getsum(pos<<1|1,l,r);
}

void update(int pos,int l,int r,long long x)
{
    if(r < tree[pos].l || tree[pos].r < l)    return;
    if(l <= tree[pos].l && tree[pos].r <= r)
    {
        tree[pos].mi += x;
        tree[pos].ma += x;
        tree[pos].sum += (tree[pos].r-tree[pos].l+1)*x;
        tree[pos].lazy += x;
        return;
    }
    pushdown(pos);
    update(pos<<1,l,r,x);
    update(pos<<1|1,l,r,x);
    pushup(pos);
}

void sq(int pos,int l,int r)
{
    if(r < tree[pos].l || tree[pos].r < l)    return;
    if(l <= tree[pos].l && tree[pos].r <= r && (long long)sqrt(tree[pos].ma)-(long long)sqrt(tree[pos].mi) == tree[pos].ma-tree[pos].mi)
    {
        long long t = tree[pos].ma-(long long)sqrt(tree[pos].ma);
        tree[pos].mi -= t;
        tree[pos].ma -= t;
        tree[pos].sum -= (tree[pos].r-tree[pos].l+1)*t;
        tree[pos].lazy -= t;
        return;
    }
    pushdown(pos);
    sq(pos<<1,l,r);
    sq(pos<<1|1,l,r);
    pushup(pos);
}

int main()
{
    ios::sync_with_stdio(0);
    cin >> n >> m;
    for(int i = 1;i <= n;i++)   cin >> a[i];
    build(1,1,n);
    for(int i = 1;i <= m;i++)
    {
        int z,l,r,x;
        cin >> z >> l >> r;
        if(z == 1)
        {
            cin >> x;
            update(1,l,r,x);
        }
        else if(z == 2) sq(1,l,r);
        else    cout << getsum(1,l,r) << endl;
    }
    return 0;
}
//UOJ228
区间加减,区间开根,询问区间和
#include<bits/stdc++.h>
using namespace std;

int n,m;
long long a[1000005];
struct segtree
{
    int l,r,max1,max2,num;
    long long sum;
}tree[4000005];

inline void pushup(int pos)
{
    tree[pos].max1 = max(tree[pos<<1].max1,tree[pos<<1|1].max1);
    tree[pos].sum = tree[pos<<1].sum+tree[pos<<1|1].sum;
    tree[pos].num = 0;
    tree[pos].max2 = max(tree[pos<<1].max2,tree[pos<<1|1].max2);
    if(tree[pos].max1 == tree[pos<<1].max1) tree[pos].num += tree[pos<<1].num;
    else    tree[pos].max2 = max(tree[pos].max2,tree[pos<<1].max1);
    if(tree[pos].max1 == tree[pos<<1|1].max1)  tree[pos].num += tree[pos<<1|1].num;
    else    tree[pos].max2 = max(tree[pos].max2,tree[pos<<1|1].max1);
}

inline void pushdown(int pos)
{
    if(tree[pos].max1 < tree[pos<<1].max1)
    {
        tree[pos<<1].sum -= (long long)tree[pos<<1].num*(tree[pos<<1].max1-tree[pos].max1);
        tree[pos<<1].max1 = tree[pos].max1;
    }
    if(tree[pos].max1 < tree[pos<<1|1].max1)
    {
        tree[pos<<1|1].sum -= (long long)tree[pos<<1|1].num*(tree[pos<<1|1].max1-tree[pos].max1);
        tree[pos<<1|1].max1 = tree[pos].max1;
    }
}

void build(int pos,int l,int r)
{
    tree[pos].l = l;
    tree[pos].r = r;
    if(l == r)
    {
        scanf("%d",&tree[pos].max1);
        tree[pos].sum = tree[pos].max1;
        tree[pos].max2 = -1;
        tree[pos].num = 1;
        return;
    }
    int mid = (l+r)/2;
    build(pos<<1,l,mid);
    build(pos<<1|1,mid+1,r);
    pushup(pos);
}

void update(int pos,int l,int r,int x)
{
    if(r < tree[pos].l || tree[pos].r < l || x >= tree[pos].max1)   return;
    if(l <= tree[pos].l && tree[pos].r <= r && tree[pos].max2 < x)
    {
        tree[pos].sum -= (long long)tree[pos].num*(tree[pos].max1-x);
        tree[pos].max1 = x;
        return;
    }
    pushdown(pos);
    update(pos<<1,l,r,x);
    update(pos<<1|1,l,r,x);
    pushup(pos);
}

long long getsum(int pos,int l,int r)
{
    if(r < tree[pos].l || tree[pos].r < l)  return 0;
    if(l <= tree[pos].l && tree[pos].r <= r)    return tree[pos].sum;
    pushdown(pos);
    return  getsum(pos<<1,l,r)+getsum(pos<<1|1,l,r);
}

int getmax(int pos,int l,int r)
{
    if(r < tree[pos].l || tree[pos].r < l)  return 0;
    if(l <= tree[pos].l && tree[pos].r <= r)    return tree[pos].max1;
    pushdown(pos);
    return max(getmax(pos<<1,l,r),getmax(pos<<1|1,l,r));
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build(1,1,n);
        for(int i = 1;i <= m;i++)
        {
            int z,l,r,x;
            scanf("%d%d%d",&z,&l,&r);
            if(z == 0)
            {
                scanf("%d",&x);
                update(1,l,r,x);
            }
            else if(z == 1) printf("%d\n",getmax(1,l,r));
            else    printf("%lld\n",getsum(1,l,r));
        }
    }
    return 0;
}
//HDU5306
区间最小值,询问区间最大值,询问区间和
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ls pos<<1
#define rs pos<<1|1
using namespace std;

int n,m;
char s[10];
long long a[1000005];
struct segtree
{
    int l,r,nmax,pmax,nlazy,plazy,ncov,pcov;
}tree[4000005];

inline void pushup(int pos)
{
    tree[pos].nmax = max(tree[ls].nmax,tree[rs].nmax);
    tree[pos].pmax = max(tree[ls].pmax,tree[rs].pmax);
}

inline void pushdown(int pos)
{
    tree[ls].pmax = max(tree[ls].pmax,max(tree[pos].pcov,tree[pos].plazy+tree[ls].nmax));
    tree[rs].pmax = max(tree[rs].pmax,max(tree[pos].pcov,tree[pos].plazy+tree[rs].nmax));
    if(tree[pos].ncov == -INF)
    {
        tree[ls].nmax += tree[pos].nlazy;
        tree[rs].nmax += tree[pos].nlazy;
        if(tree[ls].ncov == -INF)
        {
            tree[ls].plazy = max(tree[ls].plazy,tree[ls].nlazy+tree[pos].plazy);
            tree[ls].nlazy += tree[pos].nlazy;
        }
        else
        {
            tree[ls].pcov = max(tree[ls].pcov,tree[ls].ncov+tree[pos].plazy);
            tree[ls].ncov = tree[ls].nmax;
        }
        if(tree[rs].ncov == -INF)
        {
            tree[rs].plazy = max(tree[rs].plazy,tree[rs].nlazy+tree[pos].plazy);
            tree[rs].nlazy += tree[pos].nlazy;
        }
        else
        {
            tree[rs].pcov = max(tree[rs].pcov,tree[rs].ncov+tree[pos].plazy);
            tree[rs].ncov = tree[rs].nmax;
        }
    }
    else
    {
        if(tree[ls].ncov == -INF)   tree[ls].plazy = max(tree[ls].plazy,tree[ls].nlazy+tree[pos].plazy);
        else    tree[ls].pcov = max(tree[ls].pcov,tree[ls].nmax+tree[pos].plazy);
        if(tree[rs].ncov == -INF)   tree[rs].plazy = max(tree[rs].plazy,tree[rs].nlazy+tree[pos].plazy);
        else    tree[rs].pcov = max(tree[rs].pcov,tree[rs].nmax+tree[pos].plazy);
        tree[ls].nmax = tree[pos].ncov;
        tree[rs].nmax = tree[pos].ncov;
        tree[ls].ncov = tree[pos].ncov;
        tree[rs].ncov = tree[pos].ncov;
        tree[ls].pcov = max(tree[ls].pcov,tree[pos].pcov);
        tree[rs].pcov = max(tree[rs].pcov,tree[pos].pcov);
    }
    tree[pos].nlazy = 0;
    tree[pos].plazy = 0;
    tree[pos].ncov = -INF;
    tree[pos].pcov = -INF;
}

void build(int pos,int l,int r)
{
    tree[pos].l = l;
    tree[pos].r = r;
    tree[pos].ncov = -INF;
    tree[pos].pcov = -INF;
    tree[pos].nlazy = 0;
    tree[pos].plazy = 0;
    if(l == r)
    {
        scanf("%d",&tree[pos].nmax);
        tree[pos].pmax = tree[pos].nmax;
        return;
    }
    int mid = (l+r)/2;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(pos);
}

long long getans(int pos,int l,int r,int t)
{
    if(r < tree[pos].l || tree[pos].r < l)  return -INF;
    if(l <= tree[pos].l && tree[pos].r <= r)    return t?tree[pos].pmax:tree[pos].nmax;
    pushdown(pos);
    return  max(getans(ls,l,r,t),getans(rs,l,r,t));
}


void update1(int pos,int l,int r,int x)
{
    if(r < tree[pos].l || tree[pos].r < l)  return;
    if(l <= tree[pos].l && tree[pos].r <= r)
    {
        tree[pos].nmax += x;
        tree[pos].pmax = max(tree[pos].pmax,tree[pos].nmax);
        if(tree[pos].ncov == -INF)
        {
            tree[pos].nlazy += x;
            tree[pos].plazy = max(tree[pos].plazy,tree[pos].nlazy);
        }
        else
        {
            tree[pos].ncov = tree[pos].nmax;
            tree[pos].pcov = max(tree[pos].pcov,tree[pos].ncov);
        }
        return;
    }
    pushdown(pos);
    update1(ls,l,r,x);
    update1(rs,l,r,x);
    pushup(pos);
}

void update2(int pos,int l,int r,int x)
{
    if(r < tree[pos].l || tree[pos].r < l)  return;
    if(l <= tree[pos].l && tree[pos].r <= r)
    {
        tree[pos].nmax = x;
        tree[pos].pmax = max(tree[pos].pmax,tree[pos].nmax);
        tree[pos].ncov = x;
        tree[pos].pcov = max(tree[pos].pcov,tree[pos].ncov);
        return;
    }
    pushdown(pos);
    update2(ls,l,r,x);
    update2(rs,l,r,x);
    pushup(pos);
}

int main()
{
    scanf("%d",&n);
    build(1,1,n);
    scanf("%d",&m);
    for(int i = 1;i <= m;i++)
    {
        int l,r,x;
        scanf("%s%d%d",s,&l,&r);
        if(s[0] == 'Q') printf("%d\n",getans(1,l,r,0));
        else if(s[0] == 'A')    printf("%d\n",getans(1,l,r,1));
        else if(s[0] == 'P')
        {
            scanf("%d",&x);
            update1(1,l,r,x);
        }
        else
        {
            scanf("%d",&x);
            update2(1,l,r,x);
        }
    }
    return 0;
}
//TYVJ1518
区间加减,区间覆盖,询问区间最大值,询问历史区间最大值

#include<bits/stdc++.h>
using namespace std;

int n,m,a[200005],cnt[200005],next[200005],belong[200005],l[1005],r[1005];

void build()
{
    int len = sqrt(n);
    int num = (n+len-1)/len;
    if(n%len) num++;
    for(int i = 1;i <= num;i++)
    {
        l[i] = (i-1)*len+1;
        r[i] = i*len;
    }
    r[num] = n;
    for(int i = 1;i <= n;i++)   belong[i] = (i-1)/len+1;
    for(int i = n;i >= 1;i--)
    {
        int t = i+a[i];
        if(t > n)
        {
            cnt[i] = 1;
            next[i] = -1;
        }
        else if(belong[i] == belong[t])
        {
            cnt[i] = cnt[t]+1;
            next[i] = next[t];
        }
        else
        {
            cnt[i] = 1;
            next[i] = t;
        }
    }
}

void update(int pos,int x)
{
    a[pos] = x;
    for(int i = pos;i >= l[belong[pos]];i--)
    {
        int t = i+a[i];
        if(t > n)
        {
            cnt[i] = 1;
            next[i] = -1;
        }
        else if(belong[i] == belong[t])
        {
            cnt[i] = cnt[t]+1;
            next[i] = next[t];
        }
        else
        {
            cnt[i] = 1;
            next[i] = t;
        }
    }
}

int getsum(int x)
{
    int ans = cnt[x];
    while(next[x] > 0)
    {
        x = next[x];
        ans += cnt[x];
    }
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)   scanf("%d",&a[i]);
    build();
    scanf("%d",&m);
    while(m--)
    {
        int x,y,z;
        scanf("%d",&x);
        if(x == 1)
        {
            scanf("%d",&y);
            printf("%d\n",getsum(y+1));
        }
        else
        {
            scanf("%d%d",&y,&z);
            update(y+1,z);
        }
    }
    return 0;
}
块状数组
int a[30005],num[30005],n,m;
long long ans[30005];
struct node
{
    int l,r,num,belong;
    friend bool operator<(node a,node b)
    {
        if(a.belong == b.belong)    return a.r < b.r;
        return a.l < b.l;
    }
}query[30005];


int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int size = sqrt(n);
        for(int i = 1;i <= n;i++)    scanf("%d",&a[i]);
        for(int i = 1;i <= m;i++)
        {
            scanf("%d%d",&query[i].l,&query[i].r);
            query[i].num = i;
            query[i].belong = (query[i].l-1)/size+1;
        }
        sort(query+1,query+1+m);
        memset(num,0,sizeof(num));
        int ll = 1,rr = 1;
        LL now = 1;
        num[a[1]]++;
        for(int i = 1;i <= m;i++)
        {
            while(rr < query[i].r)
            {
                rr++;
                num[a[rr]]++;
                //now = ;
            }
            while(ll > query[i].l)
            {
                ll--;
                num[a[ll]]++;
                //now = ;
            }
            while(ll < query[i].l)
            {
                //now = ;
                num[a[ll]]--;
                ll++;
            }
            while(rr > query[i].r)
            {
                //now = ;
                num[a[rr]]--;
                rr--;
            }
            ans[query[i].num] = now;
        }
        for(int i = 1;i <= m;i++)    printf("%lld\n",ans[i]);
    }
    return 0;
}
莫队

//1:INSERT post tot c1,c2,...ctot :在当前数列的第pos个数字后插入tot个数字
//2:DELETE pos tot : 从当前数列的第pos个数字开始连续 删除tot个数字
//3:MAKE-SAME pos tot c :将当前数列的第pos个数字开始连续的tot个数字统一修改为c
//4:REVERSE pos tot : 翻转当前数列的第pos个数字来说的连续的tot个数字
//5:GET-SUM pos tot :计算当前数列的第pos个数字来说的连续的tot个数字的和并输出
//6:MAX-SUM :求出当前数列中和最大的一段序列,输出最大和
#include<bits/stdc++.h>
#define Key_value ch[ch[root][1]][0]
#define N 500005
#define INF 0x3f3f3f3f
using namespace std;

int n,m,a[N];
char s[20];
int pre[N],ch[N][2],key[N],size[N];
int root,tot1,tot2,st[N];
int sum[N],rev[N],same[N];
int lx[N],rx[N],mx[N];

//debug部分**********************************
void Treavel(int x)
{
    if(!x)  return;
    Treavel(ch[x][0]);
    printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d\n",x,ch[x][0],ch[x][1],pre[x],size[x]);
    Treavel(ch[x][1]);
}
void debug()
{
    printf("root:%d\n",root);
    Treavel(root);
}
//以上是debug部分**************************************


void NewNode(int &r,int father,int k)
{
    if(tot2) r = st[tot2--];//取的时候是tot2--,存的时候就是++tot2
    else r = ++tot1;
    pre[r] = father;
    ch[r][0] = ch[r][1] = 0;
    key[r] = k;
    sum[r] = k;
    rev[r] = same[r] = 0;
    lx[r] = rx[r] = mx[r] = k;
    size[r] = 1;
}

void Update_Rev(int r)
{
    if(!r)return;
    swap(ch[r][0],ch[r][1]);
    swap(lx[r],rx[r]);
    rev[r] ^= 1;
}

void Update_Same(int r,int v)
{
    if(!r)return;
    key[r] = v;
    sum[r] = v*size[r];
    lx[r] = rx[r] = mx[r] = max(v,v*size[r]);
    same[r] = 1;
}

void push_up(int r)
{
    int lson = ch[r][0], rson = ch[r][1];
    size[r] = size[lson]+size[rson]+1;
    sum[r] = sum[lson]+sum[rson]+key[r];
    lx[r] = max(lx[lson],sum[lson]+key[r]+max(0,lx[rson]));
    rx[r] = max(rx[rson],sum[rson]+key[r]+max(0,rx[lson]));
    mx[r] = max(0,rx[lson])+key[r]+max(0,lx[rson]);
    mx[r] = max(mx[r],max(mx[lson],mx[rson]));
}

void push_down(int r)
{
    if(same[r])
    {
        Update_Same(ch[r][0],key[r]);
        Update_Same(ch[r][1],key[r]);
        same[r] = 0;
    }
    if(rev[r])
    {
        Update_Rev(ch[r][0]);
        Update_Rev(ch[r][1]);
        rev[r] = 0;
    }
}

void Build(int &x,int l,int r,int father)
{
    if(l > r)   return;
    int mid = (l+r)/2;
    NewNode(x,father,a[mid]);
    Build(ch[x][0],l,mid-1,x);
    Build(ch[x][1],mid+1,r,x);
    push_up(x);
}

void Init()
{
    root = tot1 = tot2 = 0;
    ch[root][0] = ch[root][1] = size[root] = pre[root] = 0;
    same[root] = rev[root] = sum[root] = key[root] = 0;
    lx[root] = rx[root] = mx[root] = -INF;
    NewNode(root,0,-1);
    NewNode(ch[root][1],root,-1);
    for(int i = 0;i < n;i++)    scanf("%d",&a[i]);
    Build(Key_value,0,n-1,ch[root][1]);
    push_up(ch[root][1]);
    push_up(root);
}

//旋转,0为左旋,1为右旋
void Rotate(int x,int kind)
{
    int y = pre[x];
    push_down(y);
    push_down(x);
    ch[y][!kind] = ch[x][kind];
    pre[ch[x][kind]] = y;
    if(pre[y])  ch[pre[y]][ch[pre[y]][1]==y] = x;
    pre[x] = pre[y];
    ch[x][kind] = y;
    pre[y] = x;
    push_up(y);
}

//Splay调整,将r结点调整到goal下面
void Splay(int r,int goal)
{
    push_down(r);
    while(pre[r] != goal)
    {
        if(pre[pre[r]] == goal)
        {
            push_down(pre[r]);
            push_down(r);
            Rotate(r,ch[pre[r]][0] == r);
        }
        else
        {
            push_down(pre[pre[r]]);
            push_down(pre[r]);
            push_down(r);
            int y = pre[r];
            int kind = ch[pre[y]][0]==y;
            if(ch[y][kind] == r)
            {
                Rotate(r,!kind);
                Rotate(r,kind);
            }
            else
            {
                Rotate(y,kind);
                Rotate(r,kind);
            }
        }
    }
    push_up(r);
    if(goal == 0) root = r;
}

int Get_kth(int r,int k)
{
    push_down(r);
    int t = size[ch[r][0]] + 1;
    if(t == k)  return r;
    if(t > k)   return Get_kth(ch[r][0],k);
    else    return Get_kth(ch[r][1],k-t);
}

//在第pos个数后面插入tot个数
void Insert(int pos,int tot)
{
    for(int i = 0;i < tot;i++)scanf("%d",&a[i]);
    Splay(Get_kth(root,pos+1),0);
    Splay(Get_kth(root,pos+2),root);
    Build(Key_value,0,tot-1,ch[root][1]);
    push_up(ch[root][1]);
    push_up(root);
}

//删除子树
void erase(int r)
{
    if(!r)return;
    st[++tot2] = r;
    erase(ch[r][0]);
    erase(ch[r][1]);
}

//从第pos个数开始连续删除tot个数
void Delete(int pos,int tot)
{
    Splay(Get_kth(root,pos),0);
    Splay(Get_kth(root,pos+tot+1),root);
    erase(Key_value);
    pre[Key_value] = 0;
    Key_value = 0;
    push_up(ch[root][1]);
    push_up(root);
}

//将从第pos个数开始的连续的tot个数修改为c
void Make_Same(int pos,int tot,int c)
{
    Splay(Get_kth(root,pos),0);
    Splay(Get_kth(root,pos+tot+1),root);
    Update_Same(Key_value,c);
    push_up(ch[root][1]);
    push_up(root);
}

//将第pos个数开始的连续tot个数进行反转
void Reverse(int pos,int tot)
{
    Splay(Get_kth(root,pos),0);
    Splay(Get_kth(root,pos+tot+1),root);
    Update_Rev(Key_value);
    push_up(ch[root][1]);
    push_up(root);
}

//得到第pos个数开始的tot个数的和
int Get_Sum(int pos,int tot)
{
    Splay(Get_kth(root,pos),0);
    Splay(Get_kth(root,pos+tot+1),root);
    return sum[Key_value];
}

//得到第pos个数开始的tot个数中最大的子段和
int Get_MaxSum(int pos,int tot)
{
    Splay(Get_kth(root,pos),0);
    Splay(Get_kth(root,pos+tot+1),root);
    return mx[Key_value];
}

void InOrder(int r)
{
    if(!r)  return;
    push_down(r);
    InOrder(ch[r][0]);
    printf("%d ",key[r]);
    InOrder(ch[r][1]);
}



int main()
{
    scanf("%d%d",&n,&m);
    Init();
    int x,y,z;
    while(m--)
    {
        scanf("%s",s);
        if(strcmp(s,"INSERT") == 0)
        {
            scanf("%d%d",&x,&y);
            Insert(x,y);
        }
        else if(strcmp(s,"DELETE") == 0)
        {
            scanf("%d%d",&x,&y);
            Delete(x,y);
        }
        else if(strcmp(s,"MAKE-SAME") == 0)
        {
            scanf("%d%d%d",&x,&y,&z);
            Make_Same(x,y,z);
        }
        else if(strcmp(s,"REVERSE") == 0)
        {
            scanf("%d%d",&x,&y);
            Reverse(x,y);
        }
        else if(strcmp(s,"GET-SUM") == 0)
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",Get_Sum(x,y));
        }
        else if(strcmp(s,"MAX-SUM") == 0)   printf("%d\n",Get_MaxSum(1,size[root]-2));
    }
    return 0;
}
splay tree

//动态维护一组森林,要求支持一下操作:
//link(a,b) : 如果a,b不在同一颗子树中,则通过在a,b之间连边的方式,连接这两颗子树
//cut(a,b)  : 如果a,b在同一颗子树中,且a!=b,则将a视为这颗子树的根以后,切断b与其父亲结点的连接
//ADD(a,b,w): 如果a,b在同一颗子树中,则将a,b之间路径上所有点的点权增加w
//query(a,b): 如果a,b在同一颗子树中,返回a,b之间路径上点权的最大值
#include<bits/stdc++.h>
#define N 300005
using namespace std;

int n,q,op;
int ch[N][2],pre[N],key[N];
int add[N],rev[N],Max[N];
bool rt[N];
vector<int> v[N];

void Update_Add(int r,int d)
{
    if(!r)return;
    key[r] += d;
    add[r] += d;
    Max[r] += d;
}

void Update_Rev(int r)
{
    if(!r)return;
    swap(ch[r][0],ch[r][1]);
    rev[r] ^= 1;
}

void push_down(int r)
{
    if(add[r])
    {
        Update_Add(ch[r][0],add[r]);
        Update_Add(ch[r][1],add[r]);
        add[r] = 0;
    }
    if(rev[r])
    {
        Update_Rev(ch[r][0]);
        Update_Rev(ch[r][1]);
        rev[r] = 0;
    }
}

void push_up(int r)
{
    Max[r] = max(max(Max[ch[r][0]],Max[ch[r][1]]),key[r]);
}

void Rotate(int x)
{
    int y = pre[x], kind = ch[y][1] == x;
    ch[y][kind] = ch[x][!kind];
    pre[ch[y][kind]] = y;
    pre[x] = pre[y];
    pre[y] = x;
    ch[x][!kind] = y;
    if(rt[y])
    {
        rt[y] = 0;
        rt[x] = 1;
    }
    else    ch[pre[x]][ch[pre[x]][1]==y] = x;
    push_up(y);
}

//P函数先将根结点到r的路径上所有的结点的标记逐级下放
void P(int r)
{
    if(!rt[r])  P(pre[r]);
    push_down(r);
}

void Splay(int r)
{
    P(r);
    while(!rt[r])
    {
        int f = pre[r],ff = pre[f];
        if(rt[f])   Rotate(r);
        else if((ch[ff][1] == f) == (ch[f][1] == r))
        {
            Rotate(f);
            Rotate(r);
        }
        else
        {
            Rotate(r);
            Rotate(r);
        }
    }
    push_up(r);
}

int Access(int x)
{
    int y = 0;
    for(;x;x = pre[y = x])
    {
        Splay(x);
        rt[ch[x][1]] = 1;
        rt[ch[x][1]=y] = 0;
        push_up(x);
    }
    return y;
}

//判断是否是同根(真实的树,非splay)
bool judge(int u,int v)
{
    while(pre[u])   u = pre[u];
    while(pre[v])   v = pre[v];
    return u == v;
}

//使r成为它所在的树的根
void mroot(int r)
{
    Access(r);
    Splay(r);
    Update_Rev(r);
}

//调用后u是原来u和v的lca,v和ch[u][1]分别存着lca的2个儿子
//(原来u和v所在的2颗子树)
void lca(int &u,int &v)
{
    Access(v),v = 0;
    while(u)
    {
        Splay(u);
        if(!pre[u]) return;
        rt[ch[u][1]] = 1;
        rt[ch[u][1] = v] = 0;
        push_up(u);
        u = pre[v = u];
    }
}

void link(int u,int v)
{
    if(judge(u,v))
    {
        puts("-1");
        return;
    }
    mroot(u);
    pre[u] = v;
}

//使u成为u所在树的根,并且v和它父亲的边断开
void cut(int u,int v)
{
    if(u == v || !judge(u,v))
    {
        puts("-1");
        return;
    }
    mroot(u);
    Splay(v);
    pre[ch[v][0]] = pre[v];
    pre[v] = 0;
    rt[ch[v][0]] = 1;
    ch[v][0] = 0;
    push_up(v);
}

void ADD(int u,int v,int w)
{
    if(!judge(u,v))
    {
        puts("-1");
        return;
    }
    lca(u,v);
    Update_Add(ch[u][1],w);
    Update_Add(v,w);
    key[u] += w;
    push_up(u);
}

void query(int u,int v)
{
    if(!judge(u,v))
    {
        puts("-1");
        return;
    }
    lca(u,v);
    printf("%d\n",max(max(Max[v],Max[ch[u][1]]),key[u]));
}

void init()
{
    for(int i = 1;i <= n;i++)   v[i].clear();
    for(int i = 0;i <= n;i++)
    {
        pre[i] = 0;
        ch[i][0] = ch[i][1] = 0;
        rev[i] = 0;
        add[i] = 0;
        rt[i] = 1;
    }
    Max[0] = -2000000000;
}

void dfs(int u)
{
    for(int i = 0;i < v[u].size();i++)
    {
        int t = v[u][i];
        if(pre[t] != 0)continue;
        pre[t] = u;
        dfs(t);
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i = 1;i < n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&key[i]);
            Max[i] = key[i];
        }
        scanf("%d",&q);
        pre[1] = -1;
        dfs(1);
        pre[1] = 0;
        while(q--)
        {
            scanf("%d",&op);
            if(op == 1)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                link(x,y);
            }
            else if(op == 2)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                cut(x,y);
            }
            else if(op == 3)
            {
                int w,x,y;
                scanf("%d%d%d",&w,&x,&y);
                ADD(x,y,w);
            }
            else
            {
                int x,y;
                scanf("%d%d",&x,&y);
                query(x,y);
            }
        }
        printf("\n");
    }
    return 0;
}
动态树LCT

主席树:

int n,q,m,tot,a[N],b[N];
int tree[N],lson[N*30],rson[N*30],c[N*30];

void init_hash()
{
    for(int i = 1;i <= n;i++) b[i]=a[i];
    sort(b+1,b+n+1);
    m = unique(b+1,b+n+1)-b-1;
}

int gethash(int x)
{
    return lower_bound(b+1,b+1+m,x)-b;
}

void build(int &now,int l,int r)
{
    now = tot++;
    c[now] = 0;
    if(l == r)  return;
    int mid = (l+r)/2;
    build(lson[now],l,mid);
    build(rson[now],mid+1,r);
}

void update(int &now,int last,int l,int r,int pos,int x)
{
    now = tot++;
    lson[now] = lson[last];
    rson[now] = rson[last];
    c[now] = c[last]+x;
    if(l == r)  return;
    int mid = (l+r)/2;
    if(pos <= mid)  update(lson[now],lson[last],l,mid,pos,x);
    else    update(rson[now],rson[last],mid+1,r,pos,x);
}

int query(int lt,int rt,int l,int r,int k)
{
    if(l == r)  return l;
    int mid = (l+r)/2;
    if(c[lson[rt]]-c[lson[lt]] >= k)    return query(lson[lt],lson[rt],l,mid,k);
    return query(rson[lt],rson[rt],mid+1,r,k-c[lson[rt]]+c[lson[lt]]);
}

int main()
{
    ios::sync_with_stdio(0);
    while(~scanf("%d%d",&n,&q))
    {
        for(int i = 1;i <= n;i++)   scanf("%d",&a[i]);
        init_hash();
        tot = 0;
        build(tree[0],1,m);
        for(int i = 1;i <= n;i++)    update(tree[i],tree[i-1],1,m,gethash(a[i]),1);
        while(q--)
        {
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",b[query(tree[l-1],tree[r],1,m,k)]);
        }
    }
    return 0;
}
静态区间第k大
int n,q,m,tot,a[N],b[N];
int tree[N],lson[N*100],rson[N*100],c[N*100];
map<int,int> mp;

int build(int l,int r)
{
    int now = tot++;
    c[now] = 0;
    if(l == r)  return now;
    int mid = (l+r)/2;
    lson[now] = build(l,mid);
    rson[now] = build(mid+1,r);
    return now;
}

int update(int last,int pos,int x)
{
    int now = tot++,t = now;
    c[now] = c[last]+x;
    int l = 1,r = n;
    while(l < r)
    {
        int mid  = (l+r)/2;
        if(pos <= mid)
        {
            lson[now] = tot++;
            rson[now] = rson[last];
            now = lson[now];
            last = lson[last];
            r = mid;
        }
        else
        {
            rson[now] = tot++;
            lson[now] = lson[last];
            now = rson[now];
            last = rson[last];
            l = mid+1;
        }
        c[now] = c[last]+x;
    }
    return t;
}

int query(int pos,int now,int l,int r)
{
    if(l == r)  return c[now];
    int mid = (l+r)/2;
    if(pos <= mid)  return query(pos,lson[now],l,mid)+c[rson[now]];
    return query(pos,rson[now],mid+1,r);
}

int main()
{

    while(~scanf("%d",&n))
    {
        for(int i = 1;i <= n;i++)   scanf("%d",&a[i]);
        tot = 0;
        tree[0] = build(1,n);
        for(int i = 1;i <= n;i++)
        {
            if(mp.find(a[i]) == mp.end())   tree[i] = update(tree[i-1],i,1);
            else
            {
                int t = update(tree[i-1],mp[a[i]],-1);
                tree[i] = update(t,i,1);
            }
            mp[a[i]] = i;
        }
        scanf("%d",&q);
        while(q--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d\n",query(l,tree[r],1,n));
        }
    }
    return 0;
}
静态区间查询不同的数个数
int n,q,m,tot,cnt,a[N],b[N],p[N],f[N*2],rmq[N*2];
int tree[N],lson[N*40],rson[N*40],c[N*40];
vector<int> v[N];
struct ST
{
    int mm[2*N],dp[2*N][20];
    void init(int n)
    {
        mm[0] = -1;
        for(int i = 1;i <= n;i++)
        {
            mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
            dp[i][0] = i;
        }
        for(int j = 1;j <= mm[n];j++)
        {
            for(int i = 1;i+(1<<j)-1 <= n;i++)  dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
        }
    }
    int query(int a,int b)
    {
        if(a > b)   swap(a,b);
        int k = mm[b-a+1];
        return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
    }
}st;

void inithash()
{
    for(int i = 1;i <= n;i++)   b[i] = a[i];
    sort(b+1,b+1+n);
    m = unique(b+1,b+1+n)-b-1;
}

int gethash(int x)
{
    return lower_bound(b+1,b+1+m,x)-b;
}

void dfs(int now,int pre,int dep)
{
    f[++cnt] = now;
    rmq[cnt] = dep;
    p[now] = cnt;
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t == pre)    continue;
        dfs(t,now,dep+1);
        f[++cnt] = now;
        rmq[cnt] = dep;
    }
}

void initlca(int root,int n)
{
    cnt = 0;
    dfs(root,root,0);
    st.init(2*n-1);
}

int querylca(int x,int y)
{
    return f[st.query(p[x],p[y])];
}

int build(int l,int r)
{
    int now = tot++;
    c[now] = 0;
    if(l == r)  return now;
    int mid = (l+r)/2;
    lson[now] = build(l,mid);
    rson[now] = build(mid+1,r);
    return now;
}

int update(int last,int pos,int x)
{
    int now = tot++,t = now;
    c[now] = c[last]+x;
    int l = 1,r = m;
    while(l < r)
    {
        int mid  = (l+r)/2;
        if(pos <= mid)
        {
            lson[now] = tot++;
            rson[now] = rson[last];
            now = lson[now];
            last = lson[last];
            r = mid;
        }
        else
        {
            rson[now] = tot++;
            lson[now] = lson[last];
            now = rson[now];
            last = rson[last];
            l = mid+1;
        }
        c[now] = c[last]+x;
    }
    return t;
}

void dfsbuild(int now,int pre)
{
    tree[now] = update(tree[pre],gethash(a[now]),1);
    for(int i = 0;i < v[now].size();i++)
    {
        int t = v[now][i];
        if(t == pre)    continue;
        dfsbuild(t,now);
    }
}

int query(int lt,int rt,int lcat,int pos,int k,int l,int r)
{
    if(l == r)  return l;
    int mid = (l+r)/2;
    int t = c[lson[lt]]+c[lson[rt]]-2*c[lson[lcat]];
    if(pos >= l && pos <= mid)  t++;
    if(t >= k)  return query(lson[lt],lson[rt],lson[lcat],pos,k,l,mid);
    return query(rson[lt],rson[rt],rson[lcat],pos,k-t,mid+1,r);
}

int main()
{
    scanf("%d%d",&n,&q);
    for(int i = 1;i <= n;i++)   scanf("%d",&a[i]);
    inithash();
    tot = 0;
    for(int i = 1;i < n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    initlca(1,n);
    tree[0] = build(1,m);
    dfsbuild(1,0);
    while(q--)
    {
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        int t = querylca(x,y);
        printf("%d\n",b[query(tree[x],tree[y],tree[t],gethash(a[t]),k,1,m)]);
    }
    return 0;
}
树上路径点权第k大
int n,q,m,tot,a[N],b[N],use[N];;
int tree[N],tree2[N],lson[N*50],rson[N*50],c[N*50];

struct Query
{
    int kind;
    int l,r,k;
}query[10010];

void Init_hash(int k)
{
    sort(b,b+k);
    m = unique(b,b+k) - b;
}
int hash(int x)
{
    return lower_bound(b,b+m,x)-b;
}
int build(int l,int r)
{
    int root = tot++;
    c[root] = 0;
    if(l != r)
    {
        int mid = (l+r)/2;
        lson[root] = build(l,mid);
        rson[root] = build(mid+1,r);
    }
    return root;
}

int Insert(int root,int pos,int val)
{
    int newroot = tot++, tmp = newroot;
    int l = 0, r = m-1;
    c[newroot] = c[root] + val;
    while(l < r)
    {
        int mid = (l+r)>>1;
        if(pos <= mid)
        {
            lson[newroot] = tot++; rson[newroot] = rson[root];
            newroot = lson[newroot]; root = lson[root];
            r = mid;
        }
        else
        {
            rson[newroot] = tot++; lson[newroot] = lson[root];
            newroot = rson[newroot]; root = rson[root];
            l = mid+1;
        }
        c[newroot] = c[root] + val;
    }
    return tmp;
}

int lowbit(int x)
{
    return x&(-x);
}

void add(int x,int pos,int val)
{
    while(x <= n)
    {
        tree2[x] = Insert(tree2[x],pos,val);
        x += lowbit(x);
    }
}
int sum(int x)
{
    int ret = 0;
    while(x > 0)
    {
        ret += c[lson[use[x]]];
        x -= lowbit(x);
    }
    return ret;
}
int Query(int left,int right,int k)
{
    int left_root = tree[left-1];
    int right_root = tree[right];
    int l = 0, r = m-1;
    for(int i = left-1;i;i -= lowbit(i)) use[i] = tree2[i];
    for(int i = right;i ;i -= lowbit(i)) use[i] = tree2[i];
    while(l < r)
    {
        int mid = (l+r)/2;
        int tmp = sum(right) - sum(left-1) + c[lson[right_root]] - c[lson[left_root]];
        if(tmp >= k)
        {
            r = mid;
            for(int i = left-1; i ;i -= lowbit(i))
                use[i] = lson[use[i]];
            for(int i = right; i; i -= lowbit(i))
                use[i] = lson[use[i]];
            left_root = lson[left_root];
            right_root = lson[right_root];
        }
        else
        {
            l = mid+1;
            k -= tmp;
            for(int i = left-1; i;i -= lowbit(i))
                use[i] = rson[use[i]];
            for(int i = right;i ;i -= lowbit(i))
                use[i] = rson[use[i]];
            left_root = rson[left_root];
            right_root = rson[right_root];
        }
    }
    return l;
}
void Modify(int x,int p,int d)
{
    while(x <= n)
    {
        tree2[x] = Insert(tree2[x],p,d);
        x += lowbit(x);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&q);
        tot = 0;
        m = 0;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
            b[m++] = a[i];
        }
        char op[10];
        for(int i = 0;i < q;i++)
        {
            scanf("%s",op);
            if(op[0] == 'Q')
            {
                query[i].kind = 0;
                scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k);
            }
            else
            {
                query[i].kind = 1;
                scanf("%d%d",&query[i].l,&query[i].r);
                b[m++] = query[i].r;
            }
        }
        Init_hash(m);
        tree[0] = build(0,m-1);
        for(int i = 1;i <= n;i++)
            tree[i] = Insert(tree[i-1],hash(a[i]),1);
        for(int i = 1;i <= n;i++)
            tree2[i] = tree[0];
        for(int i = 0;i < q;i++)
        {
            if(query[i].kind == 0)
                printf("%d\n",b[Query(query[i].l,query[i].r,query[i].k)]);
            else
            {
                Modify(query[i].l,hash(a[query[i].l]),-1);
                Modify(query[i].l,hash(query[i].r),1);
                a[query[i].l] = query[i].r;
            }
        }
    }
    return 0;
}
树状数组+主席树 动态第k大

 

转载于:https://www.cnblogs.com/zhurb/p/7355522.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值