2017年9月28日训练总结

这一次训练是9月25日到9月28日。

这一段时间专攻树状数组专题,并取得了一些收获。

树状数组之前总结过,就是经典三种查询的题型和求逆序数问题。现在又发现一些区间条件更新条件查询也能做。树状数组可以开多维来解决问题,也可以用不常规的写法求一些特殊条件的问题(例如城市和农村建路、南宁网络赛的最长子序列权值和)都可以用树状数组解决。也发现了它可以求最长上升序列。这三天看了很多博客上的资料,主要是看树状数组的题型和解题思路及代码实现。发现常规题中除了那三种基本查询问题以外,还有离线处理。我感觉树状数组剩下的几道相对比较难的题都应该和离线处理有关。基础的模板题已经没有什么问题了,三天都A的差不多。

对于一些区间覆盖的问题,我还不清楚用树状数组怎么解决。还有一些用树状数组存奇特东西的写法居然也能A,挺神奇的。从晚上回宿舍一直在想一道离线+树状数组的题,思路也不是很难,把区间右端点从小到大排序,再根据条件add、query就可以了。(做这道题差点忘了时间,忘了写博客。。。),下面给出这道题:

Problem N

Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 1   Accepted Submission(s) : 1
Problem Description
There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interval of men to make some group. K men in a group can create K*K value. The value of an interval is sum of these value of groups.  The people of same group's id must be continuous. Now we chose an interval of men and want to know there should be how many groups so the value of interval is max.
 

Input
First line is T indicate the case number. For each case first line is n, m(1<=n ,m<=100000) indicate there are n men and m query. Then a line have n number indicate the ID of men from left to right. Next m line each line has two number L,R(1<=L<=R<=n),mean we want to know the answer of [L,R].
 

Output
For every query output a number indicate there should be how many group so that the sum of value is max.
 

Sample Input
  
  
1 5 2 3 1 2 5 4 1 5 2 4
 

Sample Output
  
  
1 2
题意很简单,就是给出身份编号1—n的一个排列,i号和i-1、i+1是好朋友,要分为一组,权值为K*K,求给定区间内的人最多分为几组和最大。实际上就是看能分成几组。

思路:树状数组+离线,区间右端点从小到大排序后,从第一个人开始插入。当插入第i个人时,与它的编号相差1的人都会被他代替,就把那两个人删掉就行。插入到等于右端点的人时,查询多少组并存到ans数组里。

代码:

#include<iostream>
#include<cmath>
#include<string>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstdio>
#include<map>
#include<cstdio>
using namespace std;
const int mx=100010;
const int inf=0x7fffffff;
const double PI=acos(-1.0);
int max(int x,int y){if(x>y) return x;return y;}
int n,m,ff;
struct node{
    int x;int y;int ind;
    bool operator<(const node &a)const {return y<a.y;}
}b[mx];
struct no{
    int v;int ind;
    bool operator<(const no &a)const {return v<a.v;}
}a[mx];
int c[mx];
int ans[mx];
map<int,int>mp;
int lb(int i){return i&(-i);}
int add(int i,int d)
{
    while(i<mx) {
        c[i]+=d;
        i+=lb(i);
    }
}
int query(int i)
{
    int sum=0;
    while(i>0){
     sum+=c[i];
     i-=lb(i);
    }
    return sum;
}
int main()
{
    int t,i,j,x,y;
    char ch[2];
    int d;
    int flag;
    while(scanf("%d",&t)==1)
    {
        while(t--){
        memset(c,0,sizeof(c));
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i].v);
            //add(a[i].v,1);
            mp[a[i].v]=i;
        }
        //map[n+2]=n+5;
        //map[1]=-1;
        //sort(a+1,a+1+n);
        for(i=1;i<=m;i++)
        {
         scanf("%d%d",&b[i].x,&b[i].y);
         b[i].ind=i;
        }
        sort(b+1,b+1+m);
        j=1;
        int ss;
        for(i=1;i<=n;i++)
        {
            add(i,1);
            if(a[i].v>1&&mp[a[i].v-1]<i) {add(mp[a[i].v-1],-1);}
            if(a[i].v<n&&mp[a[i].v+1]<i) {add(mp[a[i].v+1],-1);}
            while(j<=m&&b[j].y==i) {
            int sum1=query(b[j].y)-query(b[j].x-1);
            ans[b[j].ind]=sum1;
            j++;
            }
            if(j==m+1) break;
        }
        for(i=1;i<=m;i++) printf("%d\n",ans[i]);
        //puts("");
    }
    }
    return 0;
}

接下来几天争取早日把难题都清掉,尽多的熟悉树状数组的各种用法,锻炼思维能力,争取以后遇到树状数组的中下等题目能快速A掉。

清完树状数组后,再去各网站找几个相关题目做做,然后就开始线段树,这两个重要的知识点一定要熟练。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值