2021杭电多校第一场

【Maximal submatrix】

题面:给出一个N * M矩阵,求出最大的列上升子矩阵

1.矩阵处理

for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j] >= mp[i-1][j])
                    mp1[i][j] = mp1[i-1][j] + 1;
                else
                    mp1[i][j] = 1;
            }
        }

 接下来问题转换为 对该矩阵求最大的子矩阵大小

 如上图,我们可以把每一行的数字考虑为一个高为mp1[i][j]的方块,利用单调栈分别求解每一行的最大子矩形面积复杂度为O(N * M)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
#include<functional>
#include<time.h>
#include<stdlib.h>
#include<sstream>
#include <iomanip>
#include<list>
#include "assert.h"
using namespace std;
#define Pair pair<int, int>
#define ULL unsigned long long
#define LS l,mid,lson
#define RS mid+1,r,rson
#define MEM(a,x) memset(a,x,sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define ll long long
#define esp 1e-8
#define lowbit(x) (x&-x)
#define girlfriend zy
#define E exp(1.0)
#define PI acos(-1.0)
//#define int long long
#define pb(x) push_back(x)
#define debug(x) cout<<#x<<" "<<x<<endl;
#define rtf return false;
#define rtt return true;
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
void puty(){puts("YES");}
void putn(){puts("NO");}
const int maxn = 4e5 + 10;
const int MOD = 1e9 + 7;
const int mod = 998244353;
const int INF = 0x3f3f3f3f; ///1 061 109 567
const int maxx = 1e7 + 10;
int mp[2020][2020];
int mp1[2020][2020];
int n,m;
struct node
{
    int val,cnt;
};
node x[2020];
int getarea(int a[])
{
    int ans = 0;
    for(int i = 1 ;i <= m;i++)
    {
        x[i].val = a[i];
        x[i].cnt = i;
    }
    stack<node> st;
    x[m+1].val = 0;
    st.push(x[1]);
    for(int i=1;i<=m+1;i++)
    {
        if(x[i].val > st.top().val)
            st.push(x[i]);
        else
        {
            int left = 0;
            while(!st.empty() && x[i].val <= st.top().val)
            {
                node j;
                j = st.top();
                st.pop();
                ans = max(ans,(i - j.cnt) * j.val);
                left = j.cnt;
            }
            x[i].cnt = left;
            st.push(x[i]);
        }
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&mp[i][j]);
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j] >= mp[i-1][j])
                    mp1[i][j] = mp1[i-1][j] + 1;
                else
                    mp1[i][j] = 1;
            }
        }
        int ans = 0;
        for(int i=1;i<=n;i++)
        {
            ans = max(ans,getarea(mp1[i]));
        }
        printf("%d
",ans);
    }

}
View Code

 

【Xor sum】

题面:给出n个数,找到最短的区间异或和大于等于K 若没有则输出" - 1 "

思路:01字典树处理区间异或最大值,同时更新区间长度和左右端点

(1)区间异或处理:处理整个数组的前缀异或和(每个前缀和的值与整个字典树查找最大值与K的关系) 操作完成之后再将这个值插入字典树

    ————原理(假设当前枚举到的前缀和在数组中的位置为R  众所周知a[r]  ^ a[l]  =  a[l  —> r -1]的异或和 )

    由X xor X = 0 ; 0 xor Y = Y;所有【l,r】 = 【1,r】 XOR 【1,l - 1】 
    这样在一颗加入了r 前的所有前缀异或和的01字典树上查找【1,r】就能得到以r为右边界的最大异或和

(2)然后你需要一个Cnt数组 记录 当前这个节点的值 在数组中最靠右边的位置 因为你要区间最小(好好理解)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
#include<functional>
#include<time.h>
#include<stdlib.h>
#include<sstream>
#include <iomanip>
#include<list>
#include "assert.h"
using namespace std;
#define Pair pair<int, int>
#define ULL unsigned long long
#define LS l,mid,lson
#define RS mid+1,r,rson
#define MEM(a,x) memset(a,x,sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define ll long long
#define esp 1e-8
#define lowbit(x) (x&-x)
#define girlfriend zy
#define E exp(1.0)
#define PI acos(-1.0)
//#define int long long
#define pb(x) push_back(x)
#define debug(x) cout<<#x<<" "<<x<<endl;
#define rtf return false;
#define rtt return true;
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
void puty(){puts("YES");}
void putn(){puts("NO");}
const int maxn = 1e7 + 10;
const int MOD = 1e9 + 7;
const int mod = 998244353;
const int INF = 0x3f3f3f3f; ///1 061 109 567
int tree[maxn][2];
int a[maxn];
int cnt[maxn];
int tot = 0;
int k;
void insert(int x,int pos)
{
    int s = 0,tmp;
    for(int i=31;i>=0;i--)
    {
        tmp = x >> i & 1;
        if(!tree[s][tmp])
            tree[s][tmp] = ++tot;
        s = tree[s][tmp];
        cnt[s] = max(cnt[s],pos);
    }
}
int get(int x)
{
    int s = 0,tmpk,tmpx;
    int l = 0;
    for(int i=31;i>=0;i--)
    {
        tmpx = x >> i & 1;
        tmpk = k >> i & 1;
        if(!tmpx)
        {
            if(!tmpk)
            {
                l = max(l,cnt[tree[s][1]]);
                if(!tree[s][0]) return l;
                   s = tree[s][0];
            }
            else
            {
                if(!tree[s][1]) return l;
                    s = tree[s][1];
            }
        }
        else
        {
            if(!tmpk)
            {
                l = max(l,cnt[tree[s][0]]);
                if(!tree[s][1]) return l;
                    s = tree[s][1];
            }
            else
            {
                if(!tree[s][0]) return l;
                    s = tree[s][0];
            }
        }
    }
    return l = max(l,cnt[s]);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d%d",&n,&k);
        for(int i=0;i<=tot;i++)
        {
            tree[i][0] = tree[i][1] = 0;
            cnt[i] = 0;
        }
        tot = 0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i] ^= a[i-1];
        }
        int ans = INF;
        int ansl = 0,ansr = 0;
        insert(0,0);
        for(int i=1;i<=n;i++)
        {
            int l = get(a[i]);
            if(l && i - l < ans)
            {
                ans = i - l;
                ansl = l + 1;
                ansr = i;
            }
            insert(a[i],i);
        }
        if(ans != INF)
        {
            printf("%d %d
",ansl,ansr);
        }
        else
        {
            printf("-1
");
        }
    }
}
View Code

【KD-Graph】

思路:按边从小到大排序,维护连通块数量 等于K时 答案 = e[i-1].val 然后跟 e[i].val比较 如果相等 输出 “-1" 不相等输出e[i-1].val

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
#include<functional>
#include<time.h>
#include<stdlib.h>
#include<sstream>
#include <iomanip>
#include<list>
#include "assert.h"
using namespace std;
#define Pair pair<int, int>
#define ULL unsigned long long
#define LS l,mid,lson
#define RS mid+1,r,rson
#define MEM(a,x) memset(a,x,sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define ll long long
#define esp 1e-8
#define lowbit(x) (x&-x)
#define girlfriend zy
#define E exp(1.0)
#define PI acos(-1.0)
//#define int long long
#define pb(x) push_back(x)
#define debug(x) cout<<#x<<" "<<x<<endl;
#define rtf return false;
#define rtt return true;
// lower_bound(a.begin(),a.end(),tmp,greater<ll>()) 第一个小于等于的
void puty(){puts("YES");}
void putn(){puts("NO");}
const int maxn = 1e7 + 10;
const int MOD = 1e9 + 7;
const int mod = 998244353;
const int INF = 0x3f3f3f3f; ///1 061 109 567
struct node
{
    int from,to,val;
    node(int u,int v,int w)
    {
        from = u,to = v,val = w;
    }
    node(){};
}e[maxn];
int head[maxn];
int pre[maxn];
int find(int x)
{
    if(x == pre[x])
        return x;
    return pre[x] = find(pre[x]);
}
void uoin(int x,int y)
{
    int fx = find(x);
    int fy = find(y);
    if(fx == fy)
        return;
    pre[fx] = fy;
}
int cmp(node a,node b)
{
    return a.val < b.val;
}
int main()
{
//    freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
        {
            head[i] = -1;
            pre[i] = i;
        }
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            e[i] = {node{u,v,w}};
        }
        sort(e+1,e+1+m,cmp);
        int ans = 0;
        int comp = 0;
        int tot = n;
        for(int i=1;i<=m;i++)
        {
            int fx = find(e[i].from);
            int fy = find(e[i].to);
            if(tot == k)
            {
                ans = e[i-1].val;
                comp = e[i].val;
            }
            if(fx != fy)
            {
                uoin(fx,fy);
                tot--;
            }
        }
        if(comp == ans)
        {
            printf("-1
");
        }
        else
        {
            printf("%d
",ans);
        }
    }
}
View Code

【zoto】

思路:莫队按x轴分块维护每一个块的区间,然后用树状数组维护(线段树T了 Orz)对跟Y轴平行方向上的点的个数 

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
#include<functional>
#include<time.h>
#include<stdlib.h>
using namespace std;
#define Pair pair<int, int>
#define ULL unsigned long long
#define LS l,mid,lson
#define RS mid+1,r,rson
#define MEM(a,x) memset(a,x,sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define ll long long
#define N 10
#define EXP 1e-8
#define lowbit(x) (x&-x)
#define girlfriend zy
#define E exp(1.0)
#define PI acos(-1.0)
//#define int long long
#define pb(x) push_back(x)
#define debug(x) cout<<#x<<" "<<x<<endl;
void puty(){puts("YES");}
void putn(){puts("NO");}
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int fx[100010],b[100010];
int vis[100010],ans[100010],fen[100010];
void modify(int x,int k) {
    for(int i=x; i<100010; i+=lowbit(i)) b[i]+=k;
}

int get(int x) {
    int ans = 0;
    for(int i=x; i; i-=lowbit(i)){
        ans+=b[i];
    }
    return ans;
}

int query(int x,int y) {
    return get(y)-get(x-1);
}

struct sut{
    int id,lx,ly,rx,ry;
}a[100010];
bool cmp(sut m,sut n){
    return fen[m.lx]==fen[n.lx]?m.rx<n.rx:fen[m.lx]<fen[n.lx];
}
void add(int x){
    if(!vis[fx[x]]){
        modify(fx[x],1);
    }
    vis[fx[x]]++;
}
void delet(int x){
    if(vis[fx[x]]==1){
        modify(fx[x],-1);
    }
    vis[fx[x]]--;
}

int main(){
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        memset(vis,0,sizeof vis);
        memset(b,0,sizeof(b));
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>fx[i];
            fx[i]++;
            fen[i]=(i -1 )/ sqrt(n) + 1;
        }
        for(int i=1;i<=m;i++){
            int lx,ly,rx,ry;
            cin>>lx>>ly>>rx>>ry;
            ly++;
            ry++;
            a[i]={i,lx,ly,rx,ry};
        }
        sort(a+1,a+1+m,cmp);
        int xl=1,xr=0;
        for(int i=1;i<=m;i++){
            while(a[i].lx<xl){
                add(--xl);
            }
            while(a[i].rx>xr){
                add(++xr);
            }
            while(a[i].lx>xl){
                delet(xl++);
            }
            while(a[i].rx<xr){
                delet(xr--);
            }
            ans[a[i].id]=query(a[i].ly,a[i].ry);
        }
        for(int i=1;i<=m;i++){
            cout<<ans[i]<<endl;
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lightWh1te/p/15037942.html