Share files on WebDAV on OpenWrt

Lookas2001 copyright, this work is licensed under the knowledge sharing signature 4 international license agreement. Please indicate the author and source when reusing.

OpenWrt (https://openwrt.org/) is a very powerful router firmware, and many functions can be achieved by installing software packages. WebDAV (http://www.webdav.org/) is an extension to HTTP, which can be used to share files. So we can try to install the corresponding software package on OpenWrt and let the device support WebDAV.

Compared to SMB, AFP, in actual testing, the speed of WebDAV is more dominant. This may benefit from the fact that WebDAV is based on HTTP, and the HTTP server may have some black technology to increase speed when reducing occupancy (or possibly because WebDAV in the next step is based on HTTP instead of HTTPS).

Another reason for writing this article is that SMB and AFP already have relatively complete tutorials, such as these two articles, https://openwrt.org/docs/guide-user/services/nas/samba_configuration https://openwrt.org/docs/guide-user/services/nas/netatalk_configuration, but WebDAV lacks documentation.

Lighttpd (https://www.lighttpd.net/) is a lightweight, yet fully functional HTTP server. It is observed that he provides WebDAV mod, so it can be used to implement WebDAV server.

Install Lighttpd and WebDAV Auth module

before Opkg update To update the local package information.

adopt Opkg install lighttpd lighttpd-mod-webdav lighttpd-mod-auth lighttpd-mod-authn_file You can install the key packages that you rely on.

If the download speed is slow or download is difficult, you can manually download the corresponding package on http://downloads.openwrt.org, install it, or set up a network agent (this is not the scope of this article, you need to find your own way).

Configure Lighttpd

Unlike SMB, which provides UCI unified configuration interface, Lighttpd needs to be modified under /etc/lighttpd.

adopt VI /etc/lighttpd/lighttpd.conf Open the main configuration file of lighttpd.

May pass CP /etc/lighttpd/lighttpd.conf /etc/lighttpd/lighttpd.conf.bak Set up a backup to restore when configuration is wrong.

This is a configured configuration file:

 /mnt "
server.upload-dirs = (" /tmp ") 
server.errorlog =" /var/log/lighttpd/error.log "
server.pid-file =" /var/run/lighttpd.pid "
server.username =" HTTP "= =" (")", "=" "," "("), "(") "," (")", "(") "," (")", "(") "," (")," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "=", "=", "=", "=", "=", "=", "=", "=", "=", "=", "=", "=", "," = "," = "," = "," = "," = "," = "," = "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "(") "," (")", "("), "(") "," (")", "(") "," (")", "server.document-root ="

The annotation in the lighttpd configuration file is implemented by adding "a" in front of the line.

Here are some changes.

Server.document-root = "/mnt" The document root is set to /mnt I added two hard disks to the router, which are mounted on /mnt/sda1 and /mnt/sdb1 respectively. This storage location is not fixed and can be adjusted according to your own preferences.

Server.port = 81 That is, the port we used to access later, the 80 port has been occupied by the uHTTPd with the system, and another conflict prevention is set up here.

Server.errorlog-use-syslog = "enable" This option can output the error log to syslog, so that we can see the error in the web console.

Server.dir-listing = "enable" , Dir-listing.encoding = "UTF-8" These two options enable you to enable listing of file functions and prevent file name garbled.

Configure WebDAV module

adopt VI /etc/lighttpd/conf.d/30-webdav.conf Open the main configuration file of lighttpd.

This is a configured configuration file:

 #######################################################################
##
##  WebDAV Module
## ---------------
##
## See https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModWebDAV
##
server.modules += ( "mod_webdav" )

#$HTTP["url"] =~ "^/dav($|/)" {
  ##
  ## enable webdav for this location
  ##
  webdav.activate = "enable"

  ##
  ## By default the webdav url is writable.
  ## Uncomment the following line if you want to make it readonly.
  ##
  webdav.is-readonly = "enable"

  ##
  ## Log the XML Request bodies for debugging
  ##
  #webdav.log-xml = "disable"

  ##
  ##
  ##
  webdav.sqlite-db-name = "/tmp/lighttpd-webdav.db"
#}
##
#######################################################################

Here are some changes.

Notes have been dropped. HTTP["URL"] = ~ "^/dav". { , } The two line, the purpose of installing Lighttpd here is to WebDAV, and annotate these two rows to set the whole website to WebDAV.

Webdav.activate = "enable" WebDAV has been enabled for the entire site.

Webdav.is-readonly = "enable" Set the operation mode in read-only mode. Set up here. Disable You can disable read-only (readable, readable).

"/mnt/sda1/.lighttpd-webdav.db" Here, we need to set up a database storage location for the WebDAV module. The location is recommended to be selected on the hard disk. This database file needs to store some attributes besides locking, if it is stored in places that are easy to lose. /tmp It will lead to data loss. Storage in addition to the location outside the hard disk will shorten the lifetime of flash memory (flash erasure upper limit). Please note that Lighttpd needs to write permission to store location directory. Chmod a+w XXX To grant permission.

Ref

  • Contents of OpenWrt forum https://forum.openwrt.org/t/webdav-configuration-essense-with-lighttpd-on-openwrt/25357
  • Document https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModWebDAV provided by Lighttpd

Configure Auth module

This configuration is used to enhance the security of your files, but it is not necessary, and the configuration can only enhance a little security. Attackers can still intercept passwords halfway. If you want to better enhance the security, please configure HTTPS.

adopt VI /etc/lighttpd/conf.d/20-auth.conf Open the main configuration file of lighttpd.

This is a configured configuration file:

 #######################################################################
##
##  Authentication Module
## -----------------------
##
## See https://redmine.lighttpd.net/projects/lighttpd/wiki/docs_modauth
## for more info.
##
server.modules += ( "mod_auth" )

auth.backend                 = "plain"
auth.backend.plain.userfile  = "/etc/lighttpd/lighttpd.user"
#auth.backend.plain.groupfile = "/etc/lighttpd/lighttpd.group"

#auth.backend.ldap.hostname = "localhost"
#auth.backend.ldap.base-dn  = "dc=my-domain,dc=com"
#auth.backend.ldap.filter   = "(uid=$)"

auth.require               = ( "/" =>
                               (
                                 "method"  => "basic",
                                 "realm"   => "Personal File Server",
                                 "require" => "valid-user"
                               ),
                             )

##
#######################################################################

Here are some changes.

It may be the carelessness of the baling personnel. There is no original configuration file. Server.modules + = ("mod_auth") One line, in order to enable this module, must be manually added.

Auth.backend = "plain" Set the authentication backend to Plain

Auth.backend.plain.userfile = "/etc/lighttpd/lighttpd.user" Set the location of authenticated backend to store authentication information.

Auth.require =... To cancel the annotation here means that authentication is enabled.

"/" This is the total station.

"Method" = > "basic" The type of authentication is set to Basic For better client compatibility.

"Realm" = > "Personal File Server". That is, when prompted, the message can be set at random.

adopt Touch /etc/lighttpd/lighttpd.user We can create the authentication information file we need.

adopt VI /etc/lighttpd/lighttpd.user Edit and authenticated information file.

This is a sample:

 User1:password1
user2:password2

See user name and password. : Separated, separated by empty lines between multiple users.

Ref

  • Document https://redmine.lighttpd.net/projects/lighttpd/wiki/docs_modauth provided by Lighttpd

Min_25 sift learning notes (pseudo)

Recommended blog: https://blog.csdn.net/qq_33229466/article/details/79679027

Below, the understanding of some corners and corners.

By factoring all the numbers into factoring factors, we consider that the number is classified according to the first prime factor and its number (p^e). We find that the sum of this class can extract a f (p^e) by the nature of the product function, that is, the formula will become f (p^e) (f (a_1 / p^e) + F (a_2 / p^e) +... ) It can be found that the latter part of the formula is a very similar problem. This is probably the main idea of Min_25 sieves.

Specifically, two summation functions are defined. One summation function (h in Zhu Zhenting's paper and G on most blogs on the Internet) assists another evaluation function (that is, G in G papers, and S in most blogs on the Internet).

The evaluation process of the auxiliary evaluation function is very similar to the process of the Ehrlich sieve, so this method is also called the extended Ehrlich sieve method.

Space use only needs O (\sqrt n), because each recursive form is like (all is the division of downward rounding) n - > n / I, N / I - > n / I / J, and the RGP / g / V can be equivalent to (/ *). Number theory is divided into blocks.

What is the complexity of Zhu Zhenting's thesis?

Here are some mathematical formulas (which should be without pots). The code directly sets those formulas. The template is in Counting Divisors.

Product function: F (x)

Ask for F (p^e) = \sum_k a_k (E) p^k

Auxiliary summation function: H_k (n, J) = \sum_{2 \leq I \leq N and (I's least prime factor > p_j or I is prime number)}

if P_j > \sqrt n Yes, there is. H_k (n, J) = h_k (n, J - 1) ;

Otherwise, there is H_k (n, J) = h_k (n, J - 1) - p_j^k (h_k (\lfloor \frac n{p_j}\rfloor, J - 1) - - (H 1 - 1 -))

In particular, for J = 0 Yes, there is. H_k (n, J) = \sum_{2 \leq I \leq n} i^k

Shorthand H_k (n) = h_k (n, J) among P_j > \sqrt n (that is, the auxiliary summation function we do not have at last).

Summation function: G (n, m) = \sum_{2 \leq I \leq N and (I's least prime factor > p_m)} f (f)

knowable G (n, m) = \sum_k a_k (1) (H (n) - H (p_m)) + \sum_{p_m. < p_j\leq + 1.

P_0 When Zero Just handle it.

G (n, 0) That is what we want.

 #include <cstdio>
#include <cstring>

typedef unsigned long long u64;

const int MAX_SQRT_N = 1e5;

struct euler_sieve {
    static const int MAX_N = MAX_SQRT_N;
    bool f[MAX_N + 10];
    int p[MAX_N + 10];
    int p_n;

    inline void operator()(int n) {
        memset(f, 0, sizeof f);
        p_n = 0;
        for (int i = 2; i <= n; ++i) {
            if (!f[i]) {
                p[++p_n] = i;
            }
            for (int j = 1; p[j] * i <= n; ++j) {
                f[p[j] * i] = true;
                if (i % p[j] == 0) break;
            }
        }
    }
} es;

struct Min_25_sieve {
    u64 n;

    u64 b[2 * MAX_SQRT_N + 10]; // 所有可能的 n / i 值,值是从大到小的(废话)
    int b_n, sqrt_n;
    inline int locate(u64 i) { return i < sqrt_n ? b_n - i + 1 : n / i; } // 查找 b[j] == i 的位置 j 

    int d0[2 * MAX_SQRT_N + 10]; // 存储 h 函数的值,数组命名个人癖好而已。  The value of the H function is only O (\sqrt n). The location at I is not h (I), but h (b[i]) 
inline void pre_calc () {/ / compute h function 
for (int = 1; I) = = 1; * = (* 1); / / ((0)). 这里以及下面的 1 * 代表的就是 i^k (本题中 k = 0(不是输入的那个 k 啊))
        for (int j = 1; (u64)es.p[j] * es.p[j] <= n; ++j) { // 枚举质数
            for (int i = 1; (u64)es.p[j] * es.p[j] <= b[i]; ++i) { // 枚举了有用的,即 b[i] 
                d0[i] = d0[i] - 1 * (d0[locate(b[i] / es.p[j])] - d0[locate(es.p[j] - 1)]); // 一定有 p[j] - 1 < \sqrt n ,所以一定可以找到一个合法的位置(不会落在一个段内) // 由于 b[i] 的值是从大道小的,所以求值顺序是没有问题的,不用开另外一个缓存数组
            }
        }
    }

    u64 f_a0_k;
    inline u64 f_a0(int e) { return e * f_a0_k + 1; }
    inline u64 f(int p, int e) { return f_a0(e); }

    u64 calc(u64 n, int m) { // 计算 g 函数
        u64 rst = f_a0(1) * (d0[locate(n)] - d0[locate(es.p[m])]);
        for (int j = m + 1; (u64)es.p[j] * es.p[j] <= n; ++j) {
            u64 pe = es.p[j];
            for (int e = 1; (u64)pe * es.p[j] <= n; ++e, pe *= es .p[j]) {
                rst += f(es.p[j], e) * calc(n / pe, j) + f(es.p[j], e + 1);
            }
        }
        return rst;
    }

    inline u64 operator()(u64 n_, u64 f_a0_k_) {
        n = n_;
        f_a0_k = f_a0_k_;

        // 分块
        sqrt_n = 0; while ((u64)sqrt_n * sqrt_n < n) ++sqrt_n;
        b_n = 0; for (u64 i = 1; i <= n; i = n / (n / i) + 1) b[++b_n] = n / i;

        // 处理辅助求和函数
        pre_calc();

        // 求和
        es.p[0] = 0, d0[b_n + 1] = 0;
        return calc(n, 0) + 1; // + 1 是那个甩单的 1 
    }
} mns;

int main() {
    // freopen("in.in", "r", stdin);

    int tc; scanf("%d", &tc);
    // int tc = 1;
    es(MAX_SQRT_N + 5); // 筛出质数
    while (tc--) {
        u64 n, f_a0_k; scanf("%llu%llu", &n, &f_a0_k);
        printf("%llu\n", mns(n, f_a0_k));
    }

    return 0;
}

It's coming to an end.

It's coming to an end.

NOIP 2018394 points. At that time, I also thought that the score could be ignorant, but I didn't know that the players of the powerful provinces were already outside 500 points. No, actually I know, but I don't want to admit it. 3 years of time were abandoned by me, and I still did not grasp it for 1 years. By now, everything is coming to an end.

Without Tsinghua north winter camp's invitation, for me, if I want to go to Tsinghua University by way of competition, the only one left is NOI gold medal.

But no, but ah. How can I catch up with too many people in my next 6 months?

How come?

Let's end it all.

The CCF winter camp in January 24th will be my last exam. It was the first and last time in the school of Guang two.

Bless and bless my classmates who come all the way.

I hope you can achieve a good result in the NOI competition in 2019, and be careful on the way!

Thank you, thank you all the way to support me step by step, teachers and parents.

Although I didn't let you see me at the moment in the NOI arena, but in my long and short OI career, you gave me knowledge, and most importantly, warmth and companionship.

May we have the pleasure of seeing you again in the coming year.

Lookas2001

January 6th in Guangzhou

NOIP 2018 travels

Change, this is my summary of this year's NOIP, from the site selection of the Tianjin competition area to the new campus, and to CCF update the "master machine" which has been criticized for countless times by the numerous players, it can be seen that NOIP's continuous improvement and the degree of attention are constantly improving. Talk nonsense. Let's talk about the idea of this examination.

Day 1

The first question is paved the road, a simple greedy, casually playing a tree array 30min A to cut the next question (actually time is longer than 30 minutes).

I saw second questions, math and math questions. However, a simple analysis can show that if a number can be expressed by other numbers, then this number is useless. Otherwise, it must be useful (obviously). The hand played several sets of samples, and found that the thought was correct, and then played a sieve, 1H A finished and cut a problem. There is a hole in the sieve. Like Euler sieve, a mark must be made, otherwise the complexity will not guarantee that it will be properly T.

Then go to the bathroom. Take a breath of fresh air. Maybe 2.5h has passed.

Look at the third question. After reading two times, I found that it was a tree like dynamic programming. Unfortunately, my tree dynamic programming was learned last week, knocking out violence, writing a pair of shots, and getting several sets of test data to test and hand over.

The topic of Day 1 this year is that it has all been hit by the Internet, but unfortunately I haven't done it yet (ZG Dalao two months A dropped 300 topics%%%).

Day 2

After reading the question, it is found that the data of the first question is particularly magical. It is a single loop tree. It considers the upper part of the broken ring and then enumerates it. So the complexity is O (n^2), but it also requires the smallest. So the idea in the examination room is to arrange the sequence again, O (n^2logn). Considering that this year's CCF is changing the testing machine, and because there is not a lot of things that will be changed every time, there is no way to think about it. Luckily, I finally asked for my "excellent" card skills. Specifically, using vector to save edges is T.

The second question is "Cao", which is a mathematical problem. However, because of its high heart, it made a mistake in the examination. It is hard to resist. It turned out that if I hadn't had a big fortune, I would have adjusted the T3 in the last 30 minutes, otherwise it would be cool. It took me 1 hours to finish the task, but finally I decided to change the topic and reduce the loss. After the last question came out, I came back to find several sets of idiot data. I knocked on a watch and handed it up. Finally, I only got 5 points on the basis of the violence. Thank CCF for the weak data.

Third question, this is NOI Plus. No, a violent fight was made.

summary

Generally speaking, experience is OK, but the mistakes made before, this time, the time planning is really, very, very important.

In addition, I feel that this game itself is very bad, because I always insist on the principle of code readability, resulting in my code generally more than 2 times longer than others, this may be changed, after all, playing a competitive game, rather than long-term maintenance of the project.

394, I have been very satisfied with the achievement of nearly 400 points.

NOI 2019, we'll see you next year!

The picture is NOIP 2018 Tianjin examination hall, Tianjin University Beiyang garden campus.

Struggle!

Afternoon, sunlight into the study room, warm and not dazzling. It's probably the best time of life to sit in a place with the physical chemistry students who are in the team.

But I am different from them. I only have this chance. Success or failure is at the same time.

I am not an ordinary child, I will make my own career. This is what I have always told myself, past, present and future.

Come on, hold on to every minute and fight!

Ideal and reality

A pile of texts didn't recite, and a lot of things didn't work. It's very frustrating today.

In fact, you know, I know why my project has not made any significant progress since 4 years ago. Maybe I was too idealistic. I gave too many labels to me. Just like father had too many thoughts on his children, I didn't find the key, so that I couldn't achieve it. In fact, this is also part of my action. I am wrong in thinking all the time instead of doing it. It has always been TODO, not Do.

I have to rely on my wish to achieve something, or I want to be respected and respected like some celebrities, but I am wrong. I have been talking about human rights and protecting personal privacy, but if I suddenly have power and status, will I still think so? While I am protecting my personal privacy, what am I doing? I have climbed other people's achievements to spy on other people's privacy. My appeal is not vigorous. What makes people speechless is that I want others to follow my thoughts, but I don't want to admit other people's hobbies. This is a sick way of thinking.

Then again, why am I in a bad mood today? Human beings are a very amazing animal. They always have unrealistic expectations for something. In fact, I am already very good, but I want to get better, but I do not want to pay the price. It is ridiculous, but it is indeed my status quo, I need to change.

I need to change, but I am also confused. What should I change? Next, where should I go? I hope that after a few years, I will not be depressed when I see these words. Fighting!

Keep exploring, long live curiosity!

This is the first part of the lookas2001 writing program, and also part of the lookas2001 trial series.

In the lookas2001 trial series, I will understand and learn all kinds of abilities that I have never had or dare not try before, try my best to broaden my knowledge, exercise my cognitive ability, and make minor but possibly great changes for this huge world.

June 1st, international children's day. This is my seventeenth children's day. For me, this is probably the last second children's day before my adult life. Obviously, I am no longer the pure and lovely me, but I wonder why I am not, what changes have been made, and what I have gained or lost. In memory of my childhood and my passing youth, as well as the opening of this series, I will provide a direction for future exploration. Here, I write this article.

First of all, to answer the questions raised at the beginning, I think the biggest change is: I lost the curiosity I had always been proud of. Yes, no other, although I know that the world is still very large, but slowly, I become more and more lazy to explore the world, no longer willing to take steps to get out of my comfort zone. The more and more solidified learning and life, facing the computer day after day, the headaches of social networking, I feel more and more boring. Because of this, my time is getting faster and faster. It's like an upright walking corpse. Life without curiosity can be boring and insane. Oh, my God, this is really a horrible thing.

If the development of things is bestowed by the wisdom of mankind, the wisdom of human beings is the result of curiosity. As early as nineteenth Century, there was a saying in Marx's philosophy created by Marx: "contradictions within things are the source and motive force for the development of things." Now, it still has a very strong reference significance. People are exploring because they do not know what they are not clear about. As a new force in the development of the world, curiosity is always the most important thing. If you need to order the human ability, the curiosity can definitely be placed in the first batch. As wiki says, "curiosity is highly related to the development of all levels of human beings, and curiosity leads to the process of learning, and the desire to understand knowledge and skills." She strongly promotes the development of human beings, and the development of human beings can not be separated from curiosity.

We are familiar with the great masters of the human science and the great contribution of the human science to the natural and human sciences. As an example of the world's famous school MIT, the children here love pranks, and their schools have even made a pranking Museum for their pranks, which makes it impossible for us to understand the culture of the prank, but at the same time, we should think of how many of these pranky children are trying to create a curious creative prank, which is the driving force of curiosity. The growth of these people into adults is the unremitting impetus for the continued prosperity of the United States, making the United States still the most powerful country in the world so far.

Like dead wood and hard stone, a person's loss of curiosity means that he loses his ability to explore himself and the world. A country or a nation's loss of curiosity is a sign of a nation's regime change or the decline of a nation. How many generals in history have lost the defeat because of curing thinking, and how many countries have not been able to decline for years because they do not consider the results of new ideas. Now many people in the society have lost the ability to explore, inaction, moving bricks for half a lifetime, to the end of life to repent.

In the end, I also wish everyone can keep their instinct to explore the world, keep on wondering and never give up their efforts to change the world. Of course, I also want to be able to read the readers here, constantly reflect on whether they stop the pace of discovery, whether they are satisfied with the status quo and unwilling to change, and whether they have given up the ability to think.

Happy children's Day!

Long live curiosity!

finish

Man Down solution report (hdu3016 dynamic programming line tree sorting)

Http://acm.hdu.edu.cn/showproblem.php? Pid=3016

Algorithm design

To get the question, let's talk about the wooden boards according to their height, and then increase the number of them from bottom to top from 1. (we think the bottom floor number is 0). Through such a step, it is obvious that the higher the number of wooden boards is, the larger the number is.

According to the meaning, if a man is on a wooden plank, he can only drop vertically from the left or right side of the plank. We define d[i] as the maximum life value when this person reaches the I plate. If we know the value of d[i], we can introduce the corresponding value of the board on the left or right side. (d[j] = d[i] + jump to the change of the value of life on the j board). In this way, we can solve recursively from top to bottom.

But how do we know where he falls on the left or right side? We can set up a segment tree for the X axis according to the point, and then from bottom to top, according to the "X" dyeing of the board (that is, the place mark on the board covered by the board), in the process of pushing upward, it is very convenient to find out which board will jump on the left and right side of the board.

Sample code

 #include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 110000, L = 110000, INF = 0x7fffffff;

int n;

struct a_d {
    int h, l, r, v;
    int ld, rd; // left down to 
} a[N];

inline bool cmp(a_d a, a_d b) {
    return a.h < b.h;
}

struct node {
    int l, r;
    int f;
    node *lc, *rc;
} mem[2 * L];
node *memp;
node *root;

node *init(int l, int r) {
    node *p = memp++;
    p->l = l;
    p->r = r;
    p->f = 0;
    if (l == r) {
        p->lc = p->rc = NULL;
    } else {
        int mid = (l + r) >> 1; 
        p->lc = init(l, mid);
        p->rc = init(mid + 1, r);
    }
    return p;
}

inline void push_down(node *p) {
    if (p->f) {
        p->lc->f = p->f;
        p->rc->f = p->f;
        p->f = 0;
    }
}

void change(node *p, int l, int r, int f) {
    if (l <= p->l && p->r <= r) {
        p->f = f;
        return;
    }

    push_down(p);
    int mid = (p->l + p->r) >> 1;
    if (l <= mid) change(p->lc, l, r, f);
    if (mid < r) change(p->rc, l, r, f);
}

int query(node *p,  int i) {
    if (i == p->l && p->r == i) {
        return p->f;
    }

    push_down(p);
    int mid = (p->l + p->r) >> 1;
    if (i <= mid) return query(p->lc, i);
    return query(p->rc, i);
}

int d[N]; 

inline int max(int a, int b) {
    if (a > b) return a; else return b;
}

int main() {
//  freopen("input.txt", "r", stdin);

    while(scanf("%d", &n) != EOF) {
        for (int i = 1; i <= n; ++i) scanf("%d%d%d%d", &a[i].h, &a[i].l, &a[i].r, &a[i].v);
        a[0].v = 0;

        std::sort(a + 1, a + n + 1, cmp);
//      
//      for (int i = 1; i <= n; ++i) printf("%d %d %d\n", i, a[i].l, a[i].r); printf("\n");

        memp = mem;
        root = init(0, 100010);
        for (int i = 1; i <= n; ++i) { 
//          printf("%d %d %d\n", i, a[i].l, a[i].r);
            a[i].ld = query(root, a[i].l); // 注意这里不 +1 -1
            a[i].rd = query(root, a[i].r);
            change(root, a[i].l, a[i].r, i);
        }
//      
//      for (int i = 1; i <= n; ++i) printf("%d %d %d\n", i, a[i].ld, a[i].r D); 

for (int i = 0; I < = n; ++i) d[i] = -INF; 
d[n] = 100 + a[n].v; -INF (= =; (int) = (0)); (= = ((), + +); = = (=, (+, + +)); ((0)} ("" ",") ";"

HH Necklace solution report (SDOI 2009 line tree sorting offline processing)

HH has a string of beautiful shells made of necklace. HH believes that different shells will bring good luck, so every time he walks, he will pick up a section of shells and think about what they express. HH keeps collecting new shells, so his necklace is getting longer and longer.

One day, he suddenly raised a question: how many different shells contained in a shell?

This question is hard to answer. Because the necklace is really too long. So he had to turn to wise man to solve this problem.

input

The first line: an integer N, which indicates the length of the necklace.

The second line: N integers, indicating the number of shells in the necklace (numbered between 0 and 1000000).

The third line: an integer M, which represents the number of HH queries.

Next, M line: two integers per row, L and R (1 or less than L R or N), indicating the interval of inquiry.

N is less than 50000, M is less than 200000.

output

M row, each row of an integer, in turn, ask for answers.

sample input

 6
1 2343 5
3
1 2
3 5
2 6

sample output

 2
2
4

source

SDOI 2009

online judge

Lydsy

Vjudge

Algorithm design

To see the topic, first of all, I want to think about the data structure I learned. At present, there is no such advanced data structure to find out the number of arbitrary intervals. Then we try to determine whether an endpoint can be obtained through simple data structure.

We need to deal with this topic offline, and sort all queries according to the size of the right nodes from small to large.

We define a variable K for the current push (or Mei Ju) to the right node, define a line segment tree, and the meaning of the j node is the number of different numbers in J-K.

We define an array of last arrays, and the I element is the last place where the I shell sequence number appears in the shell sequence.

We can find that if we advance to a new K, it is obvious that there must be a K shell serial number in these 1 to last[k] to K segments, and it does not exist in last[k] + 1 ~ k to K segments. That is reflected in the line segment tree last[i] + 1 ~ k all nodes should be + 1.

Do not understand? It doesn't matter. You can see the code below.

Sample code

 #include <cstdio>
#include <cstring>
#include <algorithm>

//using namespace std;

const int N = 55000, M = 220000, MAX = 1100000;

int n, m, a[N];

int last[N];
int idx[MAX]; // 本来是 index 但是与头文件中的函数冲突了 

struct q_d {
    int l, r, id;
} q[M];

int result[M];

inline bool cmp(q_d a, q_d b) {
    return a.r < b.r;
}

struct node {
    int l, r;
    int f;
    node *lc, *rc;
} mem[2 * N];
node *memp;
node *root;

inline void push_down(node *p) {
    if (p->f) {
        p->lc->f += p->f;
        p->rc->f += p->f;
        p->f = 0;
    }
}

node *init(int l, int r) {
    node *p = memp++;
    p->l = l;
    p->r = r;
    p->f = 0;
    if (l == r) {
        p->lc = p->rc = NULL;
    } else {
        int mid = (l + r) >> 1;
        p->lc = init(l, mid);
        p->rc = init(mid + 1, r); 
    }

    return p;
}

void change(node *p, int l, int r) {
    if (l <= p->l && p->r <= r) {
        ++p->f;
        return;
    }

    push_down(p);
    int mid = (p->l + p->r) >> 1;
    if (l <=  mid) change(p->lc, l, r);
    if (mid < r) change(p->rc, l, r);
} 

int query(node *p, int i) {
    if (p->l == p->r) {
        return p->f;
    }

    push_down(p);
    int mid = (p->l + p->r) >> 1;
    if (i <= mid) return query(p->lc, i);
    return query(p->rc, i);
}

int main() {
//  freopen("input.txt", "r", stdin);

    scanf("%d", &n);
    memset(idx, 0, sizeof idx);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", a + i);
        last[i] = idx[a[i]];
        idx[a[i]] = i;
    }

    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) {
        scanf("%d%d", &q[i].l, &q[i].r);
        q[i].id = i;
    }
    std::sort(q + 1, q + m + 1, cmp);
//  
//  for (int i = 1; i <= m; ++i) printf("%d %d\n", q[i].l, q[i].r);

    int j = 1;
    memp = mem;
    root = init(1, n);
    for (int i = 1; i <= n; ++i) {
        change(root, last[i] + 1, i); 
        for (; q[j].r == i && j <= m; ++j) {
            result[q[j].id] = query(root, q[j].l);
        }
    }

    for(int i = 1; i <= m; ++i) printf("%d\n", Result[i]); 

return 0;}

The Bakery solution report (cf833b dp with optimized DP segment tree)

Http://codeforces.com/contest/833/problem/B

NOTICE

It is recommended to read before writing this question. HH Necklace solution report (SDOI 2009 line tree sorting offline processing)

Algorithm design

Get the question for 3 minutes. This is a dynamic programming. Write code, debug, submit, at one go, finally found out at fourth points timeout. Turning to the top, it is found that when a cycle is taken to deal with each state, the overall algorithm complexity O (n ^ 3) is abandoned.

Recently, we learned the line tree, and then looked at the problem. We found that this problem was done in many different ways when we asked for the number of different numbers.

Since my description is not good enough, please look at the following code and its annotation first, first look at the definition of the global variable roughly, then look at the main function.

It is better to eat with this picture.

Sample code

 #include <cstdio>
#include <cstring>

const int N = 38500; // 35000 * 1.1 

int n, k, a[N]; // 题目中提供的数据 

int last[N]; // 记录该位置的数上一次出现的位置,last[i] 代表 a[i] 位置上的数在 a 数组中上一次出现的位置,如果没有出现过,则为 0 
int index[N]; // 用于辅助建立 last 数组 

int d[N]; // 动态规划中用于保留结果的数组, d[i] 代表在一次切割中(阶段),最后一个切割点(或者说是最后一个箱子装的最后一个蛋糕的坐标)的结果 

struct node {
    int l, r;
    int f;
    int max;
    node *lc, *rc;
} mem[2 * N];
node *memp;
node *root; // 线段树中第 i 个位置的数 为 上一个阶段 d[i] 以及 i + 1 ~ j 中不同数字的个数 的和,其中 j 为当前推进到的位置,详见下方解释 

inline void push_down(node *p) {
    if (p->f) {
        p->lc->max += p->f;
        p->lc->f += p->f; // mistake: 就像傻子一般,线段树这里给写错了 
        p->rc->max += p- >f;
        p->rc->f += p->f;
        p->f = 0;
    }
}

inline void pull_up(node *p) {
    if (p->lc->max > p->rc->max) p->max = p->lc->max; else p->max = p->rc->max;
}

node *init(int a[], int l, int r) {
    node *p = memp++;
    p->l = l;
    p->r = r;
    p->f = 0;
    if (l == r) {
        p->lc = p->rc = NULL;
        p->max = a[l];
    } else {
        int mid = (l + r) >> 1;
//      printf("%d %d %d\n", l, mid, r);
        p->lc = init(a, l, mid);
        p->rc = init(a, mid + 1, r);
        pull_up(p);
    }
    return p;
}

void change(node *p, int l, int r) {
    if (l <= p->l && p->r <= r) {
        ++p->max;
        ++p->f;
        return;
    }

    push_down(p);
    int mid = (p->l + p->r) >> 1;
    if (l <= mid) change(p->lc, l, r);
    if (mid < r) change(p->rc, l, r);
    pull_up(p);
}

int query(node *p, int l, int r) {
    if (l <= p->l && p->r <= r) {
        return p->max;
    }

    push_down(p);
    int mid = (p->l + p->r) >> 1;
    int max = 0, tmp;
    if (l <= mid) {
        max =  query(p->lc, l, r);
    }
    if (mid < r) {
        tmp = query(p->rc, l, r);
        if (tmp > max) max = tmp;
    }
    pull_up(p); // mistake:这里的pull_up是不可或缺的 

    return max;
}
//
//void debug2() {
//  for (int i = 1; i <= n; ++i) printf("%d ", last[i]);
//  printf("\n\n");
//}
//
//void debug1() {
//  for (int i = 0; i <= n; ++i) printf("%d ", d[i]);
//  printf("\n");
//} 

int main() {
//  freopen("input.txt", "r", stdin);

    scanf("%d%d", &n, &k);
    memset(index, 0, sizeof index);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", a + i);
        last[i] = index[a[i]]; // 读取输入的过程中同时填充一下 last 数组,last 数组的含义见上定义 
        index[a[i]] = i;
    }
//  
//  debug2();

    // 动态规划,为了能够对动态规划中的一个阶段中的不同状态下的求解能够快速进行,我们使用了递推,这样求解的顺序可以利用线段树进行优化 
    memset(d, 0, sizeof d); // 不难发现最开始的结果都是  0 的 
    for (int i = 1; i <= k; ++i) { // 阶段,即切割或者说是箱子的个数 
        memp = mem;
        root = init(d, 0, n); // 线段树是可以从 0 开始建立的,详见下方解释 
        for (int j = i; j <= n; ++j) { // 枚举当前阶段切割点的位置 
            // 诚然,我们对于每一个切割点而言,我们都可以跑一次如下的循环 
            /* 
            int max = 0, tmp;
            for (int k = i - 1; k <= j - 1; ++k) { // 很明显 i - 1 之前的是不可能满足题意的 
                tmp = last_d[k] + different_num_between(k, j);
                if (tmp > max) max = tmp;
            }
            */
            // 但是这样太慢了,我们发现,计算从 k 到 j 的有多少个不同的数字这个函数被调用了很多遍,并且发现貌似每次都进行了许多无用的计算
            // 我们建立一棵线段树,定义为当推进到 j 位置的时候,线段树中第 k 个数为从 k + 1(加一是为了初始 化方便) 到 j 中不同数字的个数
            // 我们可以发现,last[j] + 1 到 j 中间是没有 a[j] 这个数的(一句废话)
            // 那也就是说,如果我们的进度推进到了 j 的话,对于所有的 在 last[j] + 1 ~ j 中的位置到 j 的不同数字种类应该会多出一个 j ,反映到数量上,就是个数 +1 
            // 映射到线段树的时候别忘了位置 -1 
            //  
            // 我们还可以发现,如果说按照上述定义,求最大值仍然需要扫描整个线段树,因为在原始的线段树上我们还需要增加上一个阶段的结果
            // 那么我们索性就在线段初始化的时候,将 d 数组作为线段树最开始的初始化用数组,这样求最大值就可以用线段树舒服的求出来了(当然线段树写错了当我没说) 
            // 
            // 被绕晕了? Mistake:, please note that here must be I 1 instead of I ();}} / / / / / / / Oh, my old fellow, the annotated code is a thorough mistake. You can look up the definition of annotations there, and understand 
change (root, last[j] + 1-1, J - 1) according to the code; 
d[j] = query (root, I - 1, J - 1); / /