2017 UESTC Training for Data Structures

2017 UESTC Training for Data Structures

A    水,找区间极差,RMQ怼上去。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 200005;

int a[N], f1[N][20], f2[N][20];
void RMQ(int n)
{
    rep(i,1,n) f1[i][0]=f2[i][0]=a[i];
    rep(j,1,19) rep(i,1,n) {
        if(i+(1<<j)-1<=n) {
            f1[i][j]=max(f1[i][j-1], f1[i+(1<<(j-1))][j-1]);
            f2[i][j]=min(f2[i][j-1], f2[i+(1<<(j-1))][j-1]);
        }
    }
}
int main()
{
    int n, q;
    scanf("%d %d", &n, &q);
        rep(i,1,n) scanf("%d", &a[i]);
        RMQ(n);
        int l, r;
        rep(i,1,q) {
            scanf("%d %d", &l, &r);
            int lg=floor(log10(r-l+1)/log10(2));
            int maxn=max(f1[l][lg], f1[r-(1<<lg)+1][lg]);
            int minn=min(f2[l][lg], f2[r-(1<<lg)+1][lg]);
            printf("%d\n", maxn-minn);
        }

    return 0;
}
View Code

C    线段树区间更新,区间求和。

题意:N个数排成一列,有三种操作。1.给一段区间内的每个数乘上一个非负整数。2.给一段区间内的每个数加上一个非负整数.3.询问一段区间的和模上P的值。

tags:由于需要区间加add和区间乘mul,需要维护两个延迟标记。对于add,修改c,则sum+=c*len(区间长度),add+c;对于mul,修改c,则sum*=c;add*=c,mul*=c。乘法分配律(add+sum)*c = add*c+sum*c;

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 100005, M = N<<2;

int n, m;
ll mod, laz1[M], laz2[M], tr[M];    //laz1[]乘的延迟标记,laz2[]加的延迟标记
void Init()
{
    rep(i,0,M-1) laz1[i]=1;
}
ll add(ll x, ll y) { return ((x%mod) + (y%mod))%mod; }
ll mul(ll x, ll y) { return ((x%mod) * (y%mod))%mod; }
void pushup(int pos)
{
    tr[pos]=add(tr[pos<<1], tr[pos<<1|1]);
}
void build(int pos, int l, int r)
{
    if(l==r) { scanf("%lld", &tr[pos]); tr[pos]%=mod; return ; }
    int mid=(l+r)>>1;
    build(pos<<1, l, mid);
    build(pos<<1|1, mid+1, r);
    pushup(pos);
}
void pushdown(int pos, int len)
{
    int lson=pos<<1, rson=pos<<1|1;
    tr[lson]= add(mul(tr[lson], laz1[pos]), (laz2[pos]*(len-(len>>1)))%mod);
    tr[rson]= add(mul(tr[rson], laz1[pos]), (laz2[pos]*(len>>1))%mod);
    laz1[lson]= mul(laz1[lson], laz1[pos]);
    laz1[rson]= mul(laz1[rson], laz1[pos]);
    laz2[lson]= add(mul(laz2[lson], laz1[pos]), laz2[pos]);
    laz2[rson]= add(mul(laz2[rson], laz1[pos]), laz2[pos]);
    laz1[pos]=1, laz2[pos]=0;
}
void update(int flag, int L, int R, int pos, int l, int r, ll c)
{
    if(L<=l && r<=R)
    {
        if(flag==1) {
            laz1[pos]=mul(laz1[pos], c);
            laz2[pos]=mul(laz2[pos], c);
            tr[pos]=mul(tr[pos], c);
        } else {
            laz2[pos]=add(laz2[pos], c);
            tr[pos]=add(tr[pos], ((r-l+1)*c)%mod);
        }
        return ;
    }
    pushdown(pos, r-l+1);
    int mid=(l+r)>>1;
    if(L<=mid) update(flag, L, R, pos<<1, l, mid, c);
    if(mid<R)  update(flag, L, R, pos<<1|1, mid+1, r, c);
    pushup(pos);
}
ll  query(int L, int R, int pos, int l, int r)
{
    if(L<=l && r<=R) return tr[pos];
    pushdown(pos, r-l+1);
    int mid=(l+r)>>1;
    ll ans=0;
    if(L<=mid) ans+=query(L, R, pos<<1, l, mid);
    if(mid<R)  ans+=query(L, R, pos<<1|1, mid+1, r);
    pushup(pos);
    return ans%mod;
}
int main()
{
    scanf("%d %lld", &n, &mod);
    Init();
    build(1, 1, n);
    scanf("%d", &m);
    int l, r, flag;   ll c;
    rep(i,1,m)
    {
        scanf("%d %d %d", &flag, &l, &r);
        if(flag!=3) {
            scanf("%lld", &c);
            update(flag, l, r, 1, 1, n, c);
        } else {
            printf("%lld\n", query(l, r, 1, 1, n));
        }
    }

    return 0;
}
View Code

D   水,树状数组

题意:n个点,每个点的rank值为x坐标不大于其x坐标,且y坐标不大于其y坐标的点的数量。(不含其自身),求出rank为0~n−1的点的数量。

tags:先对一维坐标排序,然后树状数组维护一下即可。

// D
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define fi  first
#define se  second
typedef long long ll;
const int N = 100005;

int n;
ll  tr[N], ans[N];
pair<int,int > co[N];
void add(int x, int y) {for(; x<=n; tr[x]+=y, x+=x&-x); }
ll sum(int x) {ll ans=0; for(; x>0; ans+=tr[x], x-=x&-x); return ans; }
int main()
{
    scanf("%d", &n);
    rep(i,1,n) scanf("%d %d", &co[i].fi, &co[i].se);
    sort(co+1, co+1+n);
    rep(i,1,n)
    {
        ++ans[sum(co[i].se)];
        add(co[i].se, 1);
    }
    rep(i,0,n-1) printf("%lld\n", ans[i]);

    return 0;
}
View Code

E    水,树状数组

题意:把一个给定的1~n的排列{a1,a2,…,an}(1≤ai≤n,且ai各不相同),用最少的交换次数,变换成另一个1~n的排列{b1,b2,…,bn}。并且,每次只交换相邻的两个元素。求最小的交换次数。

tags:按b[]的顺序依次计算,直接暴力肯定超时,所以强行搞了个树状数组。。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 100005;

int n, a[N], b[N], id[N], s[N];
ll ans;
void add(int x, int c) {for(; x; s[x]+=c, x-=x&-x); }
int sum(int x) {int ans=0; for(; x<=n; ans+=s[x], x+=x&-x); return ans; }
int main()
{
    scanf("%d", &n);
    int cnt=0;
    rep(i,1,n) {
        scanf("%d", &a[i]);
        id[a[i]]=i;
    }
    rep(i,1,n) {
        scanf("%d", &b[i]);
        int id1=id[b[i]], s1=sum(id1);
        ans+= (id1+s1-i);
        add(id1, 1);
    }
    printf("%lld\n", ans);

    return 0;
}
View Code

J    水,优先队列

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 200005;

int main()
{
    int n, ai;
    priority_queue<int , vector<int >, greater<int>  > q;
    scanf("%d", &n);
    rep(i,1,n) {
        scanf("%d", &ai);
        q.push(ai);
    }
    int ans=0;
    rep(i,1,n-1) {
        int x1=q.top(); q.pop();
        int x2=q.top(); q.pop();
        ans+= x1+x2,  q.push(x1+x2);
    }
    printf("%d\n", ans);

    return 0;
}
View Code

L    水,食物链原题

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<bitset>
#include<vector>
#include<set>
#include<list>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 100005;

int n, k, fa[N*3];
int ans[N], ans1;
int Find(int x) {return fa[x]==x ? x : fa[x]=Find(fa[x]); }
bool same(int a, int b) {return Find(a)==Find(b); }
void Unite(int a, int b) {
    int faa=Find(a), fab=Find(b);
    if(faa!=fab) fa[faa]=fab;
}
int main()
{
    scanf("%d %d", &n, &k);
    rep(i,1,n*3) fa[i]=i;
    int d, x, y;
    bool flag=0;
    rep(ca, 1, k)
    {
        scanf("%d %d %d", &d, &x, &y);
        if(x>n || y>n) {  ans[++ans1]=ca;  continue; }
        if(d==1)
        {
            if(same(x,y+n) || same(x,y+2*n)) ans[++ans1]=ca;
            else {
                Unite(x, y); Unite(x+n, y+n); Unite(x+2*n, y+2*n);
            }
        }
        else
        {
            if(x==y || same(x,y) || same(x,y+2*n)) ans[++ans1]=ca;
            else {
                Unite(x, y+n); Unite(x+n, y+2*n); Unite(x+2*n, y);
            }
        }
    }
    rep(i,1,ans1)
        if(i==1) printf("%d", ans[i]);
        else printf(" %d", ans[i]);

    return 0;
}
View Code

M   题目意思太迷

N   老题了,带正反的并查集

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,b,a) for (int i=b;i>=a;i--)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 2000005;

int fa[N];
int Find(int x) {return fa[x]==x ? x : fa[x]=Find(fa[x]); }
int main()
{
    int n, m, t, a, b;
    scanf("%d %d", &n, &m);
    rep(i,1,n*2) fa[i]=i;
    rep(i,1,m) {
        scanf("%d %d %d", &t, &a, &b);
        int faa1=Find(a*2-1), faa2=Find(a*2), fab1=Find(b*2-1), fab2=Find(b*2);
        if(t==1) {
            if(faa1==fab2 || faa2==fab1) {puts("NO"); return 0; }
            fa[faa1]=fab1, fa[faa2]=fab2;
        }
        else {
            if(faa1==fab1 || faa2==fab2) {puts("NO"); return 0; }
            fa[faa1]=fab2, fa[faa2]=fab1;
        }
    }
    puts("YES");

    return 0;
}
View Code

 

posted @ 2017-07-08 20:58  v9fly  阅读(199)  评论(0编辑  收藏  举报