平时四测

Posted edsheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了平时四测相关的知识,希望对你有一定的参考价值。

技术分享图片

技术分享图片

技术分享图片

技术分享图片

技术分享图片

技术分享图片

题解:

技术分享图片

可持久化并查集(今天早上现学习YY的, 启发式合并logN, 就不用路径压缩了, 不然会要N*logN*logN的空间)

 

技术分享图片
#include<bits/stdc++.h>
using namespace std;

const int M = 100005;
int n, m;
struct Node {
    int fa, siz;
    Node *ls, *rs;
}pool[M * 32], *tail = pool, *root[M];

Node * build(int lf = 1, int rg = n){
    Node *nd = ++tail;
    if(lf == rg)nd->fa = lf, nd->siz = 1;
    else{
        int mid = (lf + rg) >> 1;
        nd->ls = build(lf, mid);
        nd->rs = build(mid + 1, rg);
    }
    return nd;
}
#define Ls nd->ls, lf, mid
#define Rs nd->rs, mid + 1, rg
Node * add(int x, int fa, Node *nd, int lf = 1, int rg = n){
    Node *nnd = ++tail;
    if(lf == rg){
        nnd->fa = fa;
        nnd->siz = nd->siz;
    }
    
    else {
        int mid = (lf + rg) >> 1;
        if(x <= mid){
            nnd->rs = nd->rs;
            nnd->ls = add(x, fa, Ls);
        }
        else {
            nnd->ls = nd->ls;
            nnd->rs = add(x, fa, Rs);
        }
    }
    return nnd;
}

Node * query(int x, Node *nd, int lf = 1, int rg = n){
    if(lf == rg)return nd;
    else{
        int mid = (lf + rg) >> 1;
        if(x <= mid) return query(x, Ls);
        else return query(x, Rs);
    }
}
Node * kd(int x, int tt, Node *nd, int lf = 1, int rg = n){
    Node *nnd = ++tail;
    if(lf == rg)nnd->siz = tt, nnd->fa = nd->fa;
    else{
        int mid = (lf + rg) >> 1;
        if(x <= mid) {
            nnd->rs = nd->rs;
            nnd->ls = kd(x, tt, Ls);
        }
        else {
            nnd->ls = nd->ls;
            nnd->rs = kd(x, tt, Rs);
        }
    }
    return nnd;
}

Node * find(int x, Node *nd){
    Node *f = query(x, nd);
    if(f->fa == x) return f;
    return find(f->fa, nd);
}

int main(){
    freopen("build.in","r",stdin);
    freopen("build.out","w",stdout);
    scanf("%d%d", &n, &m);
    root[0] = build();
    int opt, x, y;
    int lst = 0;
    for(int i = 1; i <= m; i++){
        scanf("%d%d%d", &opt, &x, &y);
        x += lst, y += lst;
        if(opt == 1){
            Node *fx = find(x, root[i - 1]);
            Node *fy = find(y, root[i - 1]);
            if(fx->fa == fy->fa){
                root[i] = root[i - 1];
                continue;
            }
            int tt = fx->siz + fy->siz;
            if(fx->siz > fy->siz){    
                root[i] = add(fy->fa, fx->fa, root[i - 1]);
                root[i] = kd(fx->fa, tt, root[i]);
            }
            else {
                root[i] = add(fx->fa, fy->fa, root[i - 1]);
                root[i] = kd(fy->fa, tt, root[i]);
                //printf("%d %d
", find(1, root[i])->fa, find(2, root[i])->siz);
            }
        }
        else {
            root[i] = root[i - 1];

            Node *ans = find(y, root[x]);
            //printf("%d
", ans->fa);
            lst = ans->siz;
            printf("%d
", lst);
        }
        //printf("%d
", i);
    }
} 
View Code

 

题解的std:

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int MAXN=100005 ;
int n, m, fa[MAXN], times[MAXN], h[MAXN], nowT, size[MAXN];

struct Info{ 
    int tm, size ;
    Info(int _tm=0,int _size=0){ tm=_tm , size=_size; }
};

vector<Info> vec[MAXN] ;
vector<Info>::iterator it ;

bool cmp(const Info &a, const Info &b){
    return a.tm < b.tm ;
}

int findFa(int a){
    if(fa[a]==a) return a;
    return findFa(fa[a]) ;
}

void mergeNodes(int u,int v){
    int fu=findFa(u), fv=findFa(v) ;  
    if(fu==fv) return ;
    if(h[fu]<h[fv]) swap(fu,fv) ;
    fa[fv]=fu, size[fu]+=size[fv], times[fv]=nowT ;
    if(h[fu]==h[fv]) h[fu]++ ;
    vec[fu].push_back(Info(nowT,size[fu])) ;
}

int query(int t, int a){
    while(a!=fa[a] && times[a]<=t) a=fa[a] ;
    it=upper_bound(vec[a].begin(),vec[a].end(),Info(t,0),cmp) ;
    --it ;
    return it->size ;
}

int main(){
    freopen("build.in","r",stdin) ;
    freopen("build.out","w",stdout) ;
    scanf("%d%d",&n,&m) ;
    for(int i=1;i<=n;++i) fa[i]=i, vec[i].push_back(Info(0,1)), h[i]=1, size[i]=1 ;
    int lastans=0 ;
    for(int i=1;i<=m;++i){
        int t, u, v ;
        nowT=i ;
        scanf("%d%d%d",&t,&u,&v) ;
        u+=lastans , v+=lastans ;
        if(t==1){
            mergeNodes(u,v) ;
        }
        else if(t==2){
            printf("%d
",lastans=query(u,v)) ;
        }
    }
    return 0 ;
}
View Code

 

第二题:

技术分享图片

我开始想的是f[ i ]表示A的最大权值,  A用MAX去更新后面, B选的时候用MIN更新后面,这是误区1, DP一般是一种最优值;

误区2,我是正着更新的,但实际上选下个已经和前面没有关系了, 而是一个新局面, 并且有后效性啊;

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#ifdef WIN32
#define myLL "%I64d"
#else
#define myLL "%lld"
#endif
using namespace std;

const int MAXN=1000005 ;
int n, A[MAXN];
long long sum[MAXN], dp[MAXN] ;

int main(){
    freopen("distribute.in","r",stdin) ;
    freopen("distribute.out","w",stdout) ;
    scanf("%d",&n) ;
    for(int i=1;i<=n;++i) scanf("%d",&A[i]) ;
    for(int i=n;i>=1;--i) sum[i]=sum[i+1]+A[i] ;
    dp[n]=A[n] ;
    for(int i=n-1;i>=1;--i)
        dp[i]=max(dp[i+1], sum[i+1] - dp[i+1] + A[i]) ;
    printf(myLL"
", dp[1]) ;
    return 0 ;
}
View Code

 

第三题:

技术分享图片

技术分享图片

点双压边

技术分享图片
#include<bits/stdc++.h>
using namespace std;
const int M = 100005;

int knum, tot, low[M], dfn[M], tag[M], tp, t[M << 1], h[M], idc, q[M << 1]; 
bool vis[M << 1], isans[M << 1];

struct edge{int v, nxt;}G[M << 1];
void add(int u, int v){
    G[++tot].v = v, G[tot].nxt = h[u], h[u] = tot;
}

void tarjan(int u, int lst){
    dfn[u] = low[u] = ++idc;
    for(int i = h[u]; i; i = G[i].nxt){
        if((i^1) == lst) continue;
        int v = G[i].v;
        if(!vis[i]) vis[i] = vis[i^1] = 1, t[++tp] = i;
        if(!dfn[v]){
            tarjan(v, i);
            low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]){
                ++knum;
                int qnum = 0, cnt = 0, s;
                do{
                    s = t[tp--];
                    if(tag[G[s].v] != knum) tag[G[s].v] = knum, cnt++;
                    if(tag[G[s^1].v] != knum) tag[G[s^1].v] = knum, cnt++;
                    q[++qnum] = s;
                }while(s != i);
                if(cnt == qnum){
                    for(int i = 1; i <= qnum; i++) isans[q[i]] = isans[q[i]^1] = 1;
                }
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
}


int main(){
    freopen("find.in","r",stdin);
    freopen("find.out","w",stdout);
    int n, m;
    tot++; 
    scanf("%d%d", &n, &m);
    int u, v;
    for(int i = 1; i <= m; i++){
        scanf("%d%d", &u,&v);
        add(u, v); add(v, u);
    }
    for(int i = 1; i <= n; i++)
        if(!dfn[i]) tarjan(i, 0);
    int cnt = 0;
    for(int i = 2; i <= 2*m; i+=2)
        if(isans[i]) q[++cnt] = i/2;
    if(!cnt) return !puts("0");
    printf("%d
", cnt);
    for(int i = 1; i <= cnt; i++) printf("%d ", q[i]);
} 
View Code

 

以上是关于平时四测的主要内容,如果未能解决你的问题,请参考以下文章

开学第四测

暑假第十四测

18寒假第四测

暑假第二十四测

暑假第四测

NOI十连测 第四测 T3